网页源代码抓取工具(网络库urlliburllib库是4个模块详细解析(组图))
优采云 发布时间: 2021-12-30 23:18网页源代码抓取工具(网络库urlliburllib库是4个模块详细解析(组图))
网络库 urllib
urllib库是Python3内置的HTTP请求库,不需要单独安装。默认下载的 Python 已经收录该库。
urllib 库有 4 个模块:
1.request:最基本的HTTP请求模块,可以用来发送HTTP请求和接收来自服务器的响应数据。这个过程就像在浏览器地址栏中输入一个 URL。
2.parse:工具模块,提供了很多处理URL的API,如拆分、解析、合并等。
3.robotparser:用于识别网站的robots.txt文件,进而判断哪些网站可以爬取,哪些不能爬取。
4.错误:异常处理。如果发生请求错误,可以捕获这些异常,然后根据代码的需要进行处理。
下面,我们将介绍 urllib 库的 4 个模块。
要求
请求模块收录发送请求、获取响应、cookies、代理等相关API。在这里,我们将分别介绍如何使用它们。
发送 GET 请求
首先,我们一般在编写爬虫程序的时候,需要在开始时发送请求,然后得到响应进行处理。例如通过GET请求获取网页的源码,示例如下:
import urllib.request
response=urllib.request.urlopen("https://www.csdn.net/")
print(response.read().decode("UTF-8"))
如上代码所示,运行后,我们将得到网页的html源代码。
这里的 response 是一个 HTTPResponse 对象。通过调用它的各种方法和属性,可以进行各种处理。
比如这里我们获取CSDN主页,调用它的属性和方法,示例如下:
import urllib.request
response = urllib.request.urlopen("https://www.csdn.net/")
print("status:", response.status, " msg:", response.msg, " version:", response.version)
print(response.getheaders())
在这里,我们输出CSDN首页的响应状态码、响应消息和HTTP版本的属性,还打印了完整的响应头信息。
发送 POST 请求
request.urlopen()函数默认发送GET请求,如果需要发送POST请求,我们需要使用data命令参数,参数类型为bytes。示例代码如下:
import urllib.request
import urllib.parse
data = bytes(urllib.parse.urlencode({'username': 'name', 'age': '123456'}), encoding="UTF-8")
response = urllib.request.urlopen("http://httpbin.org/post", data=data)
print(response.read().decode("UTF-8"))
运行后,如果请求成功,会返回很多字符串数据。
请求超时处理
在实际爬虫项目中,我们都需要考虑一个关键问题,即请求超时。如果请求的URL长时间没有响应,卡在这里往往会浪费很多资源。
因此,我们需要设置一个超时时间。如果在限定时间内没有响应,我们应该重新获取或停止获取。示例代码如下:
import urllib.request
import urllib.parse
import urllib.error
import socket
data = bytes(urllib.parse.urlencode({'username': 'name', 'age': '123456'}), encoding="UTF-8")
try:
response = urllib.request.urlopen("http://httpbin.org/post", data=data, timeout=0.1)
print(response.read().decode("UTF-8"))
except urllib.error.URLError as e:
if isinstance(e.reason,socket.timeout):
print("超时处理")
finally:
print("继续爬虫的工作")
爬行动物伪装
现在任何知名的网站 都有明确的反爬虫技术。因此,我们在开发爬虫程序时,需要将我们的请求伪装成浏览器。
但是, urlopen() 没有头请求头参数。我们需要使用 request.Request() 来构造请求。示例代码如下:
import urllib.request
import urllib.parse
data = bytes(urllib.parse.urlencode({'username': 'name', 'age': '123456'}), encoding="UTF-8")
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
req = urllib.request.Request("http://httpbin.org/post", data=data, headers=headers)
response = urllib.request.urlopen(req)
print(response.read().decode("UTF-8"))
在这里,我们将爬虫程序伪装成来自 Firefox 浏览器的请求。
当然,Request 类还有很多其他的信息。下表由博主列出,供读者参考。
范围
意义
网址
用于发送请求的 URl,一个必选参数(除此参数外,其他参数可选)
数据
要提交的表单数据必须是字节类型
标题
请求头
origin_req_host
请求方的主机名或 IP 地址
无法核实
指示是否无法验证此请求。默认为False,主要表示用户没有足够的权限选择接收本次请求的结果。比如请求一个HTML图片,但是没有权限自动抓取图片,此时参数为True。
方法
用于指定请求,如GET、POST、PUT等,如果指定了data,则默认为POST请求
需要注意的是最后一个参数方法,如果在程序中指定请求是GET,并且还有数据表单数据,那么默认表单不会提交到服务器。
演戏
其实,除了根据请求头判断服务器是否是爬虫,判断爬虫最简单的方法就是判断是否是短时间内来自同一个IP的大量访问。
如果同一IP短时间内被大量访问,可以直接识别为爬虫。这时候我们就可以通过代理来伪装了。当然,在使用代理时,您应该不断更改代理服务器。
示例代码如下:
import urllib.error
from urllib.request import ProxyHandler, build_opener
proxy_handler = ProxyHandler({
'http': 'http://183.47.138.80:8888',
'http': 'http://125.78.226.217:8888'
})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://www.csdn.net/')
print(response.read().decode('UTF-8'))
except urllib.error.URLError as e:
print(e.reason)
运行后,返回到CSDN首页的源代码和之前一样。不过需要注意的是,这个code IP在博主写博客的时候是有效的,但是如果你看了这篇博文,可能是无效的。你需要找一个免费的代理服务器来自己测试。
获取饼干
一般来说,当我们使用爬虫登录网站时,会使用服务器返回的cookie进行操作。有了这个cookie,服务器就知道我们已经登录了。
那么如何获取cookie数据呢?示例如下:
import urllib.error
from urllib.request import ProxyHandler
import http.cookiejar
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
try:
response = opener.open('https://www.csdn.net/')
for item in cookie:
print("name=", item.name, " value=", item.value)
except urllib.error.URLError as e:
print(e.reason)
如上代码所示,我们可以通过http.cookiejar库进行操作,返回cookie的键值对,并打印输出。效果如下:
如果网站本身的cookie时长比较长,那么在爬虫之后,我们可以将其保存起来使用。这时候会用到 MozillaCookieJar 类和 LWPCookieJar 类。
这两个类会在获取cookie的同时以Mozilla浏览器格式和libwww-perl(LWP)格式保存cookie。示例代码如下:
import urllib.error
from urllib.request import ProxyHandler
import http.cookiejar
cookie = http.cookiejar.MozillaCookieJar('cookies.txt')
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
try:
response = opener.open('https://www.csdn.net/')
cookie.save(ignore_discard=True,ignore_expires=True)
except urllib.error.URLError as e:
print(e.reason)
运行后会生成一个cookies.txt文件,具体内容如下:
LWPCookieJar 类的使用与上面的 MozillaCookieJar 类似,这里不再赘述。至于读取,通过 cookie.load() 方法加载 Cookie。
解析
在实际爬虫处理中,我们经常会遇到各种编码问题。这些问题都可以通过 Parse 来解决。
中文编解码
比如在一些网址的请求头中,一些网站请求头会收录中文。但是默认不做任何处理,肯定会报UnicodeEncodeError。
读者可以用上面的代码在headers字典中添加一个键值对,让值取中文试试。接下来,我们需要对其进行编码,示例如下:
import urllib.parse
import base64
value = urllib.parse.urlencode({'name': '安踏'})
print("编码后的中文:", value)
print("解码后的中文:", urllib.parse.unquote(value))
#base64编码与解码
base64Value=base64.b64encode(bytes('学习网络urllib库',encoding="UTF-8"))
print("编码后的中文:", base64Value)
print("解码后的中文:", str(base64.b64decode(base64Value),"UTF-8"))
运行后效果如下:
需要注意的是,urlencode只能对url参数进行编码。例如,headers 请求头在此处编码。网站 中的一些数据是由 base64 编码的。这时候我们还需要掌握base64的解码和编码。
引用和取消引用
quote 函数也是一种编码函数,但它与 urlencode 的不同之处在于 urlencode 只能对 URL 进行编码。并且quote 可以编码任何字符串。
至于unquote是编码(解码)的逆过程,示例如下:
from urllib.parse import quote, unquote
url = 'https://www.baidu.com/s?wd=' + quote("王者荣耀")
print(url)
url = unquote(url)
print(url)
运行后效果如下:
网址解析
在前面的介绍中,我们也说过解析模块可以对 URL 进行分解、分析和合并。下面,我们就通过这些函数,举一些例子,读者就明白了。
from urllib import parse
url = 'https://www.csdn.net/'
split_result=parse.urlsplit(url);
print(split_result)
result = parse.urlparse(url)
print('scheme:', result.scheme) # 网络协议
print('netloc:', result.netloc) # 域名
print('path:', result.path) # 文件存放路径
print('query:', result.query) # 查询字符
print('fragment:', result.fragment) # 拆分文档中的特殊猫
运行后效果如下:
连接网址
对于 URL,有时我们需要组合 URL 的多个部分。比如我们在网站下爬取某张图片时,默认的前面部分基本一致,可能只是ID不同。
那么这时候我们就需要拼接第一部分的URL和ID。示例代码如下:
import urllib.parse
print(urllib.parse.urljoin('https://blog.csdn.net','liyuanjinglyj'))
print(urllib.parse.urljoin('https://blog.csdn.net','https://www.baidu.com'))
print(urllib.parse.urljoin('https://blog.csdn.net','index.html'))
print(urllib.parse.urljoin('https://blog.csdn.net/index.php','?name=30'))
运行后效果如下:
urljoin使用规则:第一个参数是base_url,是一个base URL。只能设置scheme、netloc 和path。第二个参数是url。
如果第二个参数不是完整的URL,第二个参数的值会加在第一个参数的后面,会自动加上斜线“/”。
如果第二个参数是完整的 URL,则直接返回第二个 URL。
参数转换(parse_qs 和 parse_qsl)
parse_qs 函数将多个参数拆分成一个字典,其中key为参数名,value为参数值。
parse_qsl 函数返回一个列表,每个元素是一个收录 2 个元素值的元组,第一个元素代表键,第二个元素代表值。
示例如下:
from urllib.parse import parse_qs, parse_qsl
query = "name=李元静&age=29"
print(parse_qs(query))
print(parse_qsl(query))
运行后效果如下:
两个函数只是返回形式不同的参数,内容基本匹配。同时,无论这两个函数是什么类型,转换结果都是字符串。
机器人协议
Robots协议也叫爬虫协议、机器人协议,全称是Robots Exclusing Protocol。
用于告诉爬虫和搜索引擎哪些页面可以爬取,哪些页面不能爬取。该协议通常放在一个名为robots.txt 的文本文件中,该文件位于网站 的根目录中。
需要特别注意的是,robots.txt文件只是在开发过程中用来判断哪些数据可以爬取,哪些数据不能爬取,并不阻止开发过程中的爬取操作。但是作为一个有良知的程序员,你应该尽可能地尊重这些规则。
Robots协议定义规则
robots.txt的文本文件一般有3个值:
1.User-agent:如果是*,表示对所有爬虫都有效。2. Disallow:不能爬取哪些目录资源,如Disallow:/index/,则禁止爬取索引文件中的所有资源。如果是/,则表示无法捕获网站。3.Allow:表示可以爬取哪些目录资源。例如Allow:/,表示可以捕获所有网站。该值与 Disallow 相同,但含义相反。
当然User-agent也可以禁止某些爬虫爬取,比如百度爬虫:User-agent:BaiduSpider。常用的爬虫名称如下:
爬虫名称
搜索引擎
谷歌机器人
谷歌
360蜘蛛
360搜索
宾博
必须
百度蜘蛛
百度
Robots协议分析
当然,我们在获取Robots协议的时候,一定要获取哪些资源是不可爬取的。不过,虽然可以直接通过字符串解析来完成,但是稍微复杂一些。
urllib 库的robotparser 模块提供了相应的解析API,即RobotFileParser 类。示例如下:
from urllib.robotparser import RobotFileParser
#一种解析方式
robot = RobotFileParser()
robot.set_url('https://www.csdn.net/robots.txt')
robot.read()
print(robot.can_fetch('*', 'https://blog.csdn.net/rank/list'))
#另一种解析方式
robot = RobotFileParser('https://www.csdn.net/robots.txt')
print(robot.can_fetch('*', 'https://blog.csdn.net/rank/list'))
这里使用can_fetch方法来判断是否可以根据Robots协议获取URL。这里的判断是CSDN排行榜是否可以爬取,返回True。
错误
我们已经在上面的代码中使用了异常处理。例如,在解释请求超时时,我们使用了 URLError。但它也有一个子类 HTTPError。