## 数据采集和解析

通过上一个章节，我们已经了解到了开发一个爬虫需要做的工作以及一些常见的问题，至此我们可以对爬虫开发需要做的工作以及相关的技术做一个简单的汇总，可能有些库我们之前并没有使用过，不过别担心，这些内容我们都会讲到的。

1. 下载数据 - urllib / requests / aiohttp。
2. 解析数据 - re / lxml / beautifulsoup4（bs4）/ pyquery。
3. 缓存和持久化 - pymysql / redis / sqlalchemy / peewee / pymongo。
4. 生成摘要 - hashlib。
5. 序列化和压缩 - pickle / json / zlib。
6. 调度器 - 进程 / 线程 / 协程。

### HTML页面分析

```HTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
        <h1>Hello, world!</h1>
        <p>这是一个神奇的网站！</p>
        <hr>
        <div>
            <h2>这是一个例子程序</h2>
            <p>静夜思</p>
            <p class="foo">床前明月光</p>
            <p id="bar">疑似地上霜</p>
            <p class="foo">举头望明月</p>
            <div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
        </div>
        <a class="foo" href="http://www.qq.com">腾讯网</a>
        <img src="./img/pretty-girl.png" alt="美女">
        <img src="./img/hellokitty.png" alt="凯蒂猫">
        <img src="/static/img/pretty-girl.png" alt="美女">
        <table>
            <tr>
                <th>姓名</th>
                <th>上场时间</th>
                <th>得分</th>
                <th>篮板</th>
                <th>助攻</th>
            </tr>
        </table>
    </body>
</html>
```

如果你对上面的代码并不感到陌生，那么你一定知道HTML页面通常由三部分构成，分别是：用来承载内容的Tag（标签）、负责渲染页面的CSS（层叠样式表）以及控制交互式行为的JavaScript。通常，我们可以在浏览器的右键菜单中通过“查看网页源代码”的方式获取网页的代码并了解页面的结构；当然，我们也可以通过浏览器提供的开发人员工具来了解网页更多的信息。

#### 使用requests获取页面

1. GET请求和POST请求。
2. URL参数和请求头。
3. 复杂的POST请求（文件上传）。
4. 操作Cookie。
5. 设置代理服务器。
6. 超时设置。

> 说明：关于requests的详细用法可以参考它的[官方文档](http://docs.python-requests.org/zh_CN/latest/user/quickstart.html)。

### 四种采集方式

#### 四种采集方式的比较

| 抓取方法   | 速度                  | 使用难度 | 备注                                       |
| ---------- | --------------------- | -------- | ------------------------------------------ |
| 正则表达式 | 快                    | 困难     | 常用正则表达式<br>在线正则表达式测试       |
| lxml       | 快                    | 一般     | 需要安装C语言依赖库<br>唯一支持XML的解析器 |
| Beautiful  | 快/慢（取决于解析器） | 简单     |                                            |
| PyQuery    | 较快                  | 简单     | Python版的jQuery                           |

> 说明：Beautiful的解析器包括：Python标准库（html.parser）、lxml的HTML解析器、lxml的XML解析器和html5lib。

#### BeautifulSoup的使用

1. 遍历文档树
   - 获取标签
   - 获取标签属性
   - 获取标签内容
   - 获取子（孙）节点
   - 获取父节点/祖先节点
   - 获取兄弟节点
2. 搜索树节点
   - find / find_all：字符串、正则表达式、列表、True、函数或Lambda。
   - select_one / select：CSS选择器

> 说明：更多内容可以参考BeautifulSoup的[官方文档]()。

### 实例 - 获取知乎发现上的问题链接

```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()

```

