## 数据采集和解析
通过[《网络爬虫和相关工具》](./01.网络爬虫和相关工具.md)一文,我们已经了解到了开发一个爬虫需要做的工作以及一些常见的问题,至此我们可以对爬虫开发需要做的工作以及相关的技术做一个简单的汇总,这其中可能会有一些我们之前没有使用过的第三方库,不过别担心,这些内容我们稍后都会一一讲到。
1. 下载数据 - urllib / requests / aiohttp。
2. 解析数据 - re / lxml / beautifulsoup4(bs4)/ pyquery。
3. 缓存和持久化 - pymysql / sqlalchemy / peewee/ redis / pymongo。
4. 生成数字签名 - hashlib。
5. 序列化和压缩 - pickle / json / zlib。
6. 调度器 - 进程(multiprocessing) / 线程(threading) / 协程(coroutine)。
### HTML页面分析
```HTML
首页
Hello, world!
这是一个神奇的网站!
这是一个例子程序
静夜思
床前明月光
疑似地上霜
举头望明月
腾讯网
```
如果你对上面的代码并不感到陌生,那么你一定知道HTML页面通常由三部分构成,分别是用来承载内容的Tag(标签)、负责渲染页面的CSS(层叠样式表)以及控制交互式行为的JavaScript。通常,我们可以在浏览器的右键菜单中通过“查看网页源代码”的方式获取网页的代码并了解页面的结构;当然,我们也可以通过浏览器提供的开发人员工具来了解网页更多的信息。
#### 使用requests获取页面
1. GET请求和POST请求。
```Python
```
2. URL参数和请求头。
```Python
```
3. 复杂的POST请求(文件上传)。
```Python
```
4. 操作Cookie。
```Python
```
5. 设置代理服务器。
```Python
```
> 说明:关于requests的详细用法可以参考它的[官方文档](http://docs.python-requests.org/zh_CN/latest/user/quickstart.html)。
### 四种采集方式
#### 四种采集方式的比较
| 抓取方法 | 速度 | 使用难度 | 备注 |
| ------------- | ------------------------- | -------- | ------------------------------------------ |
| 正则表达式 | 快 | 困难 | 常用正则表达式
在线正则表达式测试 |
| lxml | 快 | 一般 | 需要安装C语言依赖库
唯一支持XML的解析器 |
| BeautifulSoup | 较快/较慢(取决于解析器) | 简单 | |
| PyQuery | 较快 | 简单 | Python版的jQuery |
> 说明:BeautifulSoup可选的解析器包括:Python标准库(html.parser)、lxml的HTML解析器、lxml的XML解析器和html5lib。
#### 使用正则表达式
如果你对正则表达式没有任何的概念,那么推荐先阅读[《正则表达式30分钟入门教程》](),然后再阅读我们之前讲解在Python中如何使用正则表达式一文。
#### 使用XPath和Lxml
#### BeautifulSoup的使用
BeautifulSoup是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式。
1. 遍历文档树
- 获取标签
- 获取标签属性
- 获取标签内容
- 获取子(孙)节点
- 获取父节点/祖先节点
- 获取兄弟节点
2. 搜索树节点
- find / find_all
- select_one / select
> 说明:更多内容可以参考BeautifulSoup的[官方文档](https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html)。
#### PyQuery的使用
pyquery相当于jQuery的Python实现,可以用于解析HTML网页。
### 实例 - 获取知乎发现上的问题链接
```Python
from urllib.parse import urljoin
import re
import requests
from bs4 import BeautifulSoup
def main():
headers = {'user-agent': 'Baiduspider'}
proxies = {
'http': 'http://122.114.31.177:808'
}
base_url = 'https://www.zhihu.com/'
seed_url = urljoin(base_url, 'explore')
resp = requests.get(seed_url,
headers=headers,
proxies=proxies)
soup = BeautifulSoup(resp.text, 'lxml')
href_regex = re.compile(r'^/question')
link_set = set()
for a_tag in soup.find_all('a', {'href': href_regex}):
if 'href' in a_tag.attrs:
href = a_tag.attrs['href']
full_url = urljoin(base_url, href)
link_set.add(full_url)
print('Total %d question pages found.' % len(link_set))
if __name__ == '__main__':
main()
```