阅读 84

Python 爬虫小课 1-9 宝妈程序媛福利-育儿网问答数据抓取

本系列课程需要一定的 Python 语法基础,数据匹配将采用 Python 自带的 re 模块,故对正则表达式有一定的基础要求。 关于爬取环境的需求,Python3.5 以上版本,安装 requests 模块。

爬虫前的分析

类别页面分析

本次爬虫小课要爬取的的网站为育儿网(ask.ci123.com/) 的问答模块,我们要采集一下红框内的资料。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

对于该网站涉及的问题类型非常多,具体分类可以通过上述链接左侧的菜单获取到。如下图所示区域:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

在这里需要略微分析一下,分类地址的规律,如果没有规律,那第一步就先获取一下所有的分类地址,鼠标点击各链接发现,分类列表页链接如下:

http://ask.ci123.com/categories/show/2 http://ask.ci123.com/categories/show/3 http://ask.ci123.com/categories/show/4 http://ask.ci123.com/categories/show/{类别ID} 复制代码

在这里先不要下结论,说 ID 是依次递增的,写爬虫程序如果过早的假定一定的规则,很容易出现数据丢失的情况,所以尽量都尝试一遍。

在这里也可以直接通过查看网页源码,看一下所有的地址,当然看完之后还是为了我们可以爬取到。最终查阅到所有的地址都为http://ask.ci123.com/categories/show/{类别ID} 形式,只是最后的类别 ID 不是连续的。到这里问题分类分析完毕。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

问题列表页面分析

下面需要寻找列表页相关规律,点击任意类别之后,可以查阅到,页面数据样式都如下图所示:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

首先要做的第一件事请,就是查找分页规律,找到分页区域,鼠标依次点击分页,获取不同的分页地址。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

最后找到其规律链接地址如下:

http://ask.ci123.com/categories/show/4/all?p={页码} 复制代码

有页码规律还不够,还需要找到末页,在源码中简单检索,找到末页对应的页码即可。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

到此爬虫前的分析分析完毕了,下面开始进行爬虫逻辑编码环节,也就是整理自己的思路。

逻辑编码(伪代码)

育儿网爬虫分为如下步骤:

  1. 通过 ask.ci123.com/ 页面,获取所有的分类页面地址

  2. 循环所有的分类页面地址

  3. 获取每个分类对应的列表页面,并获取总页码

  4. 从一开始循环到总页码

  5. 上一步循环过程中过去每一页待爬取的数据

思路整理完毕,编码环节其实就是一个简单的实现过程。

爬虫正式编码

request 库 get 方法说明

对于 requests 库来说,导入并快速应用是非常容易的,先通过抓取分类页面源码来看一下基本使用。

import requests url = "http://ask.ci123.com/" # 抓取分类页面 def get_category():     res = requests.get("http://ask.ci123.com/")     print(res.text) if __name__ == "__main__":     get_category() 复制代码

以上代码中最核心的方法就是 requests.get()了,该方法为 requests 模块通过 get 方式获取网站源码,该方法中的参数说明如下:

必选参数 url

requests.get(url="http://ask.ci123.com/") 复制代码

传递 URL 参数

通过该参数可以构造出如下格式 https://www.baidu.com/s?wd=你好&rsv_spt=1&rsv_iqid=0x8dd347e100002e04。 格式如下:

import requests payload = {'key1': 'value1', 'key2': 'value2'} res = requests.get(url="http://ask.ci123.com/", params=payload) print(res.url) 复制代码

key1 为键名,value1 为键值。

定制请求头

在爬虫爬取的过程中,我们将尽量将爬虫模拟成真实的用户通过浏览器访问网站,所以很多时候需要定制浏览器请求头。格式如下:

import requests payload = {'key1': 'value1', 'key2': 'value2'} headers = {     'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)' } res = requests.get(url="http://ask.ci123.com/",                    params=payload, headers=headers) print(res.url) 复制代码

其中 headers 中可以配置更多的内容,本篇博客不做展开,只需要先记住 headers 参数即可。

Cookie

Cookie 在很多爬虫程序中属于必备内容,这里有时会存储加密信息,有时会存储用户信息,格式如下:

import requests payload = {'key1': 'value1', 'key2': 'value2'} headers = {     'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)' } cookies = dict(my_cookies='nodream') res = requests.get(url="http://ask.ci123.com/",                    params=payload, headers=headers, cookies=cookies) print(res.text) 复制代码

禁用重定向处理

有些网站会携带重定向源码,在爬取的时候需要禁止网格员自动跳转,代码如下:

r = requests.get('http://github.com', allow_redirects=False) 复制代码

超时

对于一个网络请求,有时会出现无法请求到的情况,这部分在官方手册高级部分有相应的说明,不过对于初学者可以先进行忽略超时的高级用法。

为防止服务器不能及时响应,大部分发至外部服务器的请求都应该带着 timeout 参数。在默认情况下,除非显式指定了 timeout 值,requests 是不会自动进行超时处理的。如果没有 timeout,你的代码可能会挂起若干分钟甚至更长时间。

常规代码如下:

import requests payload = {'key1': 'value1', 'key2': 'value2'} headers = {     'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)' } cookies = dict(my_cookies='nodream') res = requests.get(url="http://ask.ci123.com/",                    params=payload, headers=headers, cookies=cookies, timeout=3) print(res.text) 复制代码

高级部分参数

对于 get 方法,还有一些参数,在后续的博客中我们可能会用到,例如:

  • SSL 证书验证 (verify)

  • 客户端证书(cert)

  • 事件钩子(hooks)

  • 自定义身份验证(auth)

  • 流式请求(stream)

  • 代理(proxies)

以上参数都会出现在 get 方法中,所以 requests 库是一个非常非常强大的库。

获取所有的分类页面地址

有了上述详细的说明,在使用 requests 库去获取网页中的内容就变得简单一些了。这里需要有 Python 基础知识中 re 模块的使用与正则表达式的基础。具体的爬取代码如下:

import requests import re url = "http://ask.ci123.com/" headers = {     'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)' } # 抓取分类页面 def get_category():     res = requests.get("http://ask.ci123.com/", headers=headers)     pattern = re.compile(         r'<li><a href="/categories/show/(\d+)">', re.S)     categories_ids = pattern.findall(res.text)     print(f"获取到的分类ID如下:",categories_ids) if __name__ == "__main__":     get_category() 复制代码

循环所有的分类页面地址

在上述代码中通过re库的 findall 方法获取了所有的分类编号,用来拼接后续的待爬取页面。获取到 IDS 之后,就可以通过循环的方式获取到所有的列表页面了,具体如下:

# 抓取分类页面 def get_category():     res = requests.get("http://ask.ci123.com/", headers=headers)     pattern = re.compile(         r'<li><a href="/categories/show/(\d+)">', re.S)     categories_ids = pattern.findall(res.text)     print(f"获取到的分类ID如下:", categories_ids)     for cate in categories_ids: # 下述代码中有get_list()函数对应的代码         get_list(cate)         time.sleep(1) 复制代码

上述代码为了防止被反爬,需要增加一个延时处理,time.sleep()

获取每个分类对应的列表页面,并获取总页码

打开列表页面,首要目的先获取到总页码,本次实现的案例获取的页码途径比较简单,在列表页存在一项,数据直接在源码中可以看到,故直接抓取即可。

def get_list(cate):     # 获取总页码,循环抓取所有页     res = requests.get(         f"http://ask.ci123.com/categories/show/{cate}", headers=headers)     pattern = re.compile(         r'<a href="/categories/show/\d+/all\?p=(\d+)"', re.S)     totle = pattern.search(res.text).group(1)     for page in range(1, int(totle)):         print(f"http://ask.ci123.com/categories/show/{cate}/all?p={page}")         time.sleep(0.2) 复制代码

从 1 开始循环到总页码

本部分代码比较容易,已经在上述代码实现。结果如图所示:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

本案例收尾环节

后续的内容就变得非常容易了,对每页数据进行分析,并进行存储数据操作,下述代码未编写存储部分,抓取部分代码已经填写完整,其中存在一个非常大的正则表达式,可以参考一下,如果爬取数据不是很严格,大量的使用.*\s这些常见元字符即可。

import requests import re import time url = "http://ask.ci123.com/" headers = {     'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)' } def get_detail(text):     # 该函数实现解析页面数据,之后存储数据     pattern = re.compile(r'<li>[.\s]*<a href="/questions/show/(\d+)/" title="(.*?)" target="_blank" >.*?</a>\s*<span>(\d+)<font>.*?</font></span>\s*<a  href="/users/show/\d+" title=".*?">(.*?)</a>\s*<span>(.*?)</span>\s*</li>')     data = pattern.findall(text)     print(data)     # 数据存储代码不在编写 def get_list(cate):     # 获取总页码,循环抓取所有页     res = requests.get(         f"http://ask.ci123.com/categories/show/{cate}", headers=headers)     pattern = re.compile(         r'<a href="/categories/show/\d+/all\?p=(\d+)"', re.S)     totle = pattern.search(res.text).group(1)     for page in range(1, int(totle)):         print(f"http://ask.ci123.com/categories/show/{cate}/all?p={page}")         res = requests.get(             f"http://ask.ci123.com/categories/show/{cate}/all?p={page}", headers=headers)         time.sleep(0.2)         # 调取列表页数据提取函数         get_detail(res.text) # 抓取分类页面 def get_category():     res = requests.get("http://ask.ci123.com/", headers=headers)     pattern = re.compile(         r'<li><a href="/categories/show/(\d+)">', re.S)     categories_ids = pattern.findall(res.text)     print(f"获取到的分类ID如下:", categories_ids)     for cate in categories_ids:         get_list(cate)         time.sleep(1) if __name__ == "__main__":     get_category()


作者:梦想橡皮擦
链接:https://juejin.cn/post/7028782849469710372


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐