爬虫百例专栏连载已经结束,欢迎订阅
🙈100 篇爬虫文章合计 29.9 元,每篇只需 2.9 毛钱 🙈
🌹 橡皮擦 叨叨 🌹
本专栏为爬虫小课系列,周更 3+篇,专栏合计 9 篇文章,本专栏所有案例都将采用 requests 库编写,通过 9 个案例,让你深入理解 requests 库。
以上就是本系列专栏的核心目标。
本系列课程需要一定的 Python 语法基础,数据匹配将采用 Python 自带的 re 模块,故对正则表达式有一定的基础要求。
关于爬取环境的需求,Python3.5 以上版本,安装 requests 模块。
爬虫前的分析
类别页面分析
本次爬虫小课要爬取的的网站为育儿网(
http://ask.ci123.com/
) 的问答模块,我们要采集一下红框内的资料。
对于该网站涉及的问题类型非常多,具体分类可以通过上述链接左侧的菜单获取到。如下图所示区域:
在这里需要略微分析一下,分类地址的规律,如果没有规律,那第一步就先获取一下所有的分类地址,鼠标点击各链接发现,分类列表页链接如下:
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 不是连续的。到这里问题分类分析完毕。
问题列表页面分析
下面需要寻找列表页相关规律,点击任意类别之后,可以查阅到,页面数据样式都如下图所示:
首先要做的第一件事请,就是查找分页规律,找到分页区域,鼠标依次点击分页,获取不同的分页地址。
最后找到其规律链接地址如下:
http://ask.ci123.com/categories/show/4/all?p={页码}
有页码规律还不够,还需要找到末页,在源码中简单检索,找到末页对应的页码即可。
到此爬虫前的分析分析完毕了,下面开始进行爬虫逻辑编码环节,也就是整理自己的思路。
逻辑编码(伪代码)
育儿网爬虫分为如下步骤:
-
通过 http://ask.ci123.com/ 页面,获取所有的分类页面地址
-
循环所有的分类页面地址
-
获取每个分类对应的列表页面,并获取总页码
-
从一开始循环到总页码
-
上一步循环过程中过去每一页待爬取的数据
思路整理完毕,编码环节其实就是一个简单的实现过程。
爬虫正式编码
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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
循环所有的分类页面地址
在上述代码中通过
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(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 class="list_last_page" 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 开始循环到总页码
本部分代码比较容易,已经在上述代码实现。结果如图所示:
本案例收尾环节
后续的内容就变得非常容易了,对每页数据进行分析,并进行存储数据操作,下述代码未编写存储部分,抓取部分代码已经填写完整,其中存在一个非常大的正则表达式,可以参考一下,如果爬取数据不是很严格,大量的使用
.*\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="(.*?)" class="list_title" target="_blank" >.*?</a>\s*<span class="list_asw">(\d+)<font>.*?</font></span>\s*<a class="list_author" href="/users/show/\d+" title=".*?">(.*?)</a>\s*<span class="list_time">(.*?)</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 class="list_last_page" 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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
广宣时间
如果你想跟博主建立亲密关系,可以关注博主,或者关注博主公众号“
非本科程序员
”,了解一个非本科程序员是如何成长的。
博主 ID:
梦想橡皮擦
,希望大家点赞、评论、收藏
爬虫百例教程导航链接 :
https://blog.csdn.net/hihell/article/details/86106916