Python3 爬虫初体验

数据提取

通过 PyCharm 的包管理工具分别下载安装 requests 、bs4 、lxml 库。

requests 库

requests 是一个简洁优雅的 HTTP 库,基于 urllib3 再封装。一个 get 请求用一行代码即可实现:

1
res = requests.get('https://github.com/')

许多网站会根据 Request Header 识别请求是否来自非爬虫应用,可以通过伪造 Header 骗过,比如,把自己伪装成一个 Chrome 浏览器:

1
2
3
4
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
}
res = requests.get('https://github.com/', headers=headers)

可以通过浏览器的开发者工具获取到完整的头信息列表,做到完美伪装。

BeautifulSoup 和 lxml 库

bs4 即 BeautifulSoup ,是一个可以从 HTML 或 XML 文件中提取数据的库。它支持以多种形式遍历、查找 HTML 内容,比如 CSS 的选择器、标签类型甚至正则表达式。
BeautifulSoup 可以配合第三方 HTML 解析器使用,比如 lxml 。lxml 运行效率比标准库高,大概算是事实标准库了吧。

基于上述准备工作,即可完成大部分的静态页面内容抓取,比如,获取 GitHub 首页的 body 内容:

1
2
3
4
5
6
import requests
from bs4 import BeautifulSoup

rsp = requests.get('https://github.com/')
soup = BeautifulSoup(rsp.text, 'lxml')
print(soup.find('body')) # 打印出网页 body 内容

配合浏览器的开发者工具,可以拿到网页所有标签的 css selector,据此可以提取出更精细的数据,比如,拿到 GitHub 用户的头像:

1
2
3
4
5
rsp = requests.get('https://github.com/liangzuoting')
soup = BeautifulSoup(rsp.text, 'lxml')
img = soup.select('#js-pjax-container > div.container-xl.px-3.px-md-4.px-lg-5 > div > div.flex-shrink-0.col-12.col-md-3.mb-4.mb-md-0 > div > div.clearfix.d-flex.d-md-block.flex-items-center.mb-4.mb-md-0 > div.position-relative.d-inline-block.col-2.col-md-12.mr-3.mr-md-0.flex-shrink-0 > a > img')
if len(img) > 0:
print(img[0].get('src')) # 打印出头像图片 url

BeautifulSoup.select 函数接受一个 css selector 字符串,并返回匹配列表。

数据存储

通过 Python 内置的 csv 库,可以很方便的将提取的数据写入到 csv 文件。

1
2
3
4
5
6
7
import csv

f = open('d:\dd.csv', mode='w', newline='\n', encoding='utf-8-sig')
w = csv.writer(f)
w.writerow(['1', '二,三,四', '5\n6\n7'])
w.writerow(['11', '22,33,44', '55\n66\n77'])
f.close()

务必显式指定 newline 参数为 \n,Windows 平台下默认用 \r\n 做换行符,在 excel 里打开 csv 文件后出现空白行。

utf-8-sig 编码创建文件,能解决非 ascii 码字符乱码问题,sig 即 BOM,显式地把字节序写入到了文件里。

以换行符插入项字符串内,可实现单元格内换行。对以列表存储的动态数据,需要定义自己的字符串格式化函数:

1
2
def ls_to_str(ls):
'\n'.join(map(str, ls))

map 函数把 ls 列表项通过 str 函数依次映射成字符串,这个在列表项是自定义类型时是必须的,否则列表项只记录其地址值。

小结

爬虫入门还是很简单的,Python 完整的生态链功不可没。问题总是出在意想不到的地方,比如 Chrome 的弹窗自动拦截。通过开发者工具获取到的 selector 是拦截后页面的层级关系,导致 BeautifulSoup.select 获取的数据总是对不上。可以关闭浏览器的相关功能;或从 requests 导出完整的页面内容,保存成 HTML 文件后再解析。

评论