网页源代码抓取工具(网络库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。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线