在学习了Requests库的基本用法后,我们就可以使用Requests库进行一些最简单的网页爬取。由于目前还没有学习Beautifulsoup4库用于分析响应,目前爬虫并不能自动分析与提取响应内容。本章将使用多个样例进行网页爬取,对常见的爬虫问题进行分析并给出解决方法。主要包含商品信息查询、搜索引擎关联搜索、网络图片存储、IP地址属地查询等四个示例。
与发起一个请求的过程相同,定义将要爬取的网页URL后,我们通过requests.get()
方法向服务器请求指定网页信息,并将响应得到的Response
对象中的实体内容输出。(注意该URL被隐去,需要手动改为某个商品的链接)
import requests
url1 = 'https://item.jd.com/10000xxxxxxx.html'
r = requests.get(url1, allow_redirects=False)
print(r.status_code)
r.encoding = r.apparent_encoding
print(r.text)
但是响应时出现了问题:虽然响应状态码为200,但报文主体并不是从浏览器中看到的信息,而是返回了一段JavaScript代码,类似于HTTP中的303 See Other重定向
200
实际弹出了一个登录页面,而不是想要的商品网页
基于HTTP相关知识,我们知道,服务器了解访问网页的客户端的唯一途径是分析请求报文的头部信息。就像通过一条小缝来对一些猪和羊进行区分,我们通过观察其一部分皮毛的性状就能准确区分这两种动物;服务器通过分析请求报文头部的部分字段来区分通过浏览器访问的用户和自动访问的爬虫。而最主要的区分字段就是用户代理字段
User-Agent
。
通过比较一般浏览器和爬虫构造的请求的User-Agent
头部字段,我们很轻易地发现了网站返还给爬虫一个登录页面的原因。
#一般浏览器头部
{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36 Edg/85.0.564.51'}
#爬虫头部
{'User-Agent': 'python-requests/2.24.0'}
Requests库非常稳健地使用了自己的专属头部,仿佛在向所有人宣称:我就是个爬虫我怕谁?
结局很悲惨,访问直接被挡……
这个问题给了我们一个非常重要的教训:一般情况下大型网站都会开启用户代理(User-Agent
)自动筛选,将来自非浏览器和友好爬虫的访问全部拒绝。在保证自己的爬虫合乎道德和法律规范的情况下,当我们要爬取这类大型网站的内容时,需要进行一定的伪装。
将浏览器构造的用户代理字段作为爬虫访问的用户代理,
import requests
url1 = 'https://item.jd.com/10000xxxxxxx.html'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/85.0.4183.102 Safari/537.36 Edg/85.0.564.51'}
r = requests.get(url1, headers=headers, allow_redirects=False)
# print(r.request.headers)
print(r.status_code)
r.encoding = r.apparent_encoding
print(r.text)
这样,通过一点小小的伪装,我们成功地绕过网站的用户代理筛选,得到了网页内容
200
...
网络爬虫除了能够收集来自特定网页的信息外,也能够通过搜索引擎查找信息。搜索引擎除了为用户提供基于页面的“正常搜索”服务以外,为了方便各类应用程序使用搜索引擎服务,搜索引擎开发了API和搜索接口。应用程序通过使用API接口或是构造符合格式规范的搜索URL,搜索引擎就能够提供搜索服务并将结果返回。同样,爬虫也能够使用它们获得搜索服务。(注意,百度全站禁用除了指定友好爬虫外的所有爬虫,任何私自访问必须遵循类人原则,减少网站网络和系统资源的损耗。)
下面使用某度和某不存在的搜索引擎来介绍通过搜索接口传递搜索请求参数来实现关联搜索
注意:使用URL搜索接口关联搜索时,关键字为明文传送(不进行编码),注意访问安全性。如需要更高安全性的搜索,请使用API
查阅资料得到,某度的搜索接口格式为
https://www.baidu.com/s?wd=[key word]
#[key word]为搜索关键字
实际上,搜索页都在/s
目录下,想要搜索的关键字提供给一个名为wd
的参数,可以通过Requests库中的params
参数将搜索关键字合成到访问URL中实现搜索。
同样的,这个不存在的搜索引擎的搜索接口格式于某度大致相同
https://www.google.hk/search?q=[key word]
注意,一定要使用上面的用户代理字段,否则会返回一个验证页面阻止访问
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/85.0.4183.102 Safari/537.36 Edg/85.0.564.51',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'}
url_bd = 'http://www.baidu.com/s'
url_gg = 'https://www.google.hk/search'
# key_word = 'Hello'
key_word = input('Search something:\n')
param_bd = {'wd': key_word}
param_gg = {'q': key_word}
r = requests.get(url_bd, params=param_bd)
# r = requests.get(url_gg, params=param_gg)
print(r.status_code)
print(r.request.url)
r.encoding = r.apparent_encoding
print(r.text[:1000])
由于未知情况,使用HTTPS协议进行搜索会返回一个JavaScript
内容,要求跳转到HTTP协议,直接改为HTTP协议可以正常访问
使用Requests库发出请求得到的响应不仅是文本,当响应主体为图片时,可以将主体写入文件保存在指定目录中。需要用到os
标准库检查文件路径的合法性和存在性,以及使用file方法打开、写入文件。
import requests
import os
url = 'https://http.cat/'
# status = input('Input the Status code you want download:')
status = '200'
# status = '402'
Path = 'G:\\Downloads\\' + status + '.jpg'
url = url + status + '.jpg'
# Path = 'G:\\Downloads\\' + url.split('/')[-1]
try:
if not os.path.exists(Path):
r = requests.get(url)
with open(Path, 'wb') as f:
f.write(r.content)
print('Download Success!')
else:
print('File already exists')
except:
print('Error')
(由于示例中的服务器在外网,下载需要一定时间,请耐心等待)
有关文件操作和os
库的内容,本文不再赘述,需要了解的读者可自行搜索。
由于Python中反斜杠具有转义作用,故保存路径中的反斜杠均用两个转义(路径使用斜杠也可,同样需要两个)
在下载某些内容时,可能事先不知道文件的拓展名,也可使用如下代码替换定义路径的语句使下载保存的文件名与远程资源的URL
中的文件名相同,可能需要检查目录是否存在并创建
Path = root + url.split('/')[-1]
# root 为下载根目录,变量另外可调
# 以下为判断根目录是否存在并自动创建目录
if not os.path.exists(root):
try:
os.mkdir(root)
except:
print('Error while creating the root path')
本IP归属地查询示例主要使用ip138
网站(https://m.ip138.com/)来搜索IP地址的归属地。这个网站的IP属地查询服务提供了一个付费的API接口。对于白嫖党来说,如何不使用付费API查询呢?其实,与搜索引擎一样,我们也可以通过构造一个搜索URL实现查询,这需要手动使用一下服务并分析URL的结构。
通过观察,我们得到了该网站同样使用构造参数URL的方式向服务器发送用户需要查询的IP地址,结构如下,
https://www.ip138.com/iplookup.asp?ip=xxx.xxx.xxx.xxx
同样,我们只需要构造出这样的一个URL即可查询到想要的内容。由于缺乏beautifulsoup
库的响应解析,我们目前只能人工观察响应主体内容来得到想要的结果。
import requests
url = 'http://m.ip138.com/iplookup.asp?ip='
url = url + input('Input IP address you want search:')
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/85.0.4183.102 Safari/537.36 Edg/85.0.564.51',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'}
r = requests.get(url, headers=headers)
print(r.status_code)
r.encoding = r.apparent_encoding
print(r.text)
仅使用Requests库,我们可以方便地构造请求和粗略地获取响应信息。在本文中,我们爬取了京东商品信息,使用搜索引擎的搜索接口进行爬虫搜索,下载保存了网页中的图片,使用网站的查询接口实现IP属地查询。Requests库让我们初步认识到了爬虫的强大功能,在后续学习beautifulsoup
库与Scrapy
框架后,我们能够更加精确地提取信息和进行更加复杂的动作。