urllib库万字详解

什么是urllib库

  urllib库是Python内置的HTTP请求库,不需要额外的下载,主要有一下四大模块

urllib.request  请求模块
urllib.error  异常处理模块
urllib.parse  url解析模块
urllib.robotparser  robots.txt解析模块

urllib.request

urllib.request.urlopen()

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

- url: url 地址。
- data: 发送到服务器的其他数据对象,要求为字节流形式传递参数,即bytes形式。默认为None,以GET方法传递数据,若不为None,则使用POST放啊传递数据。
- timeout: 设置访问超时时间,单位:秒(s)。
- cafilecapath: cafile 为 CA 证书, capath 为 CA 证书的路径,使用 HTTPS 需要用到。
- cadefault: 已经被弃用。
- context: ssl.SSLContext类型,用来指定 SSL 设置。

from urllib.request import urlopen

response = urlopen("https://www.baidu.com/")
print(response.read())			# 全部读取
print(response.read(20))		# 指定读取前20行
print(response.read().decode("utf-8"))		# 解码为utf-8编码
print(response.readline())		# 读取一行内容

lines = response.readlines()		# 读取全部内容,赋值给一个列表变量
for line in lines:
	print(line)

使用data参数

import urllib.parse
import urllib.request

data = {"Word":"Hello"}

data = urllib.parse.urlencode(data).encode('utf-8')
response = urllib.request.urlopen('http://httpbin.org/post',data = data)
html = response.readlines()

for line in html:
	print(line)

使用timeout参数

import urllib.request
import urllib.error
import socket

try:
	response = urllib.request.urlopen("http://httpbin.org", timeout = 0.1)
except urllib.error.URLError as e:
	if(isinstance(e.reason, socket.timeout):
		pirnt("TIME OUT!")		

响应

状态码
  我们在对网页进行抓取时,经常需要判断网页是否可以正常访问,这里我们就可以使用 getcode() 函数获取网页状态码,返回 200 说明网页正常,返回 404 说明网页不存在:

import urllib.request
import urllib.error

try:
	response = urllib.request.urlopen("http://www.baidu.com")
except urllib.error.HTTPError as e:
	if(e.code == 404)		
		print(response.getcode())		# 404

响应头

import urllib.request

response = urllib.request.urlopen("http://httpbin.org")
print(type(response))
print(response.status)
print(response.getheaders())
print(response.getheader("Server"))

结果为

<class 'http.client.HTTPResponse'>
200
[('Date', 'Wed, 09 Feb 2022 04:20:20 GMT'), ('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '9593'), ('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true')]
gunicorn/19.9.0

urllib.request.Request类

  我们抓取网页一般需要对 headers(网页头信息)进行模拟,这时候需要使用到 urllib.request.Request 类:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

- url:url 地址。
- data:发送到服务器的其他数据对象,默认为 None。
- headers:HTTP 请求的头部信息,字典格式。
- origin_req_host:请求的主机地址,IP 或域名。
- unverifiable:很少用整个参数,用于设置网页是否需要验证,默认是False。。
- method:请求方法, 如 GET、POST、DELETE、PUT等。
from urllib import request, parse

url = "http://httpbin.org/post"
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.9 Safari/537.36"
}

data = {"name":"Germer"}
data = parse.urlencode(data).encode("utf-8")

req = request.Request(url, data=data, headers=headers, method="POST")
req.add_header("Host", "httpbin.org")       # 添加请求标头
response = request.urlopen(req)
lines = response.readlines()

for line in lines:
    print(line.decode("utf-8"))

结果为

{

  "args": {}, 

  "data": "", 

  "files": {}, 

  "form": {

    "name": "Germer"

  }, 

  "headers": {

    "Accept-Encoding": "identity", 

    "Content-Length": "11", 

    "Content-Type": "application/x-www-form-urlencoded", 

    "Host": "httpbin.org", 

    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.9 Safari/537.36", 

    "X-Amzn-Trace-Id": "Root=1-620347ea-463c469d1cc6e37114f8f842"

  }, 

  "json": null, 

  "origin": "120.219.4.162", 

  "url": "http://httpbin.org/post"

}

Handler

代理
  如果我们一直用同一个IP去请求同一个网站上的网页,久了之后可能会被该网站服务器屏蔽,因此我们可以使用代理IP来发起请求,代理实际上指的就是代理服务器。当我们使用代理IP发起请求时,服务器端显示的是代理IP的地址,即使被屏蔽了,我们可以换一个代理IP继续爬取。设置代理便是一种防止爬虫被反爬的措施。

使用代理

proxy_support = urllib.request.ProxyHandler({})

  参数是一个字典,字典的键时代理的类型,例如 http,ftp或https,字典的值就是代理的IP地址和对应的端口号。这里代理前需要加上协议,即http或者https,当请求链接是http协议时,ProxyHandler会调用http代理,当请求链接是https协议时,会调用https代理。

import urllib.request
proxy_id = "58.240.53.196:8080"
proxy_headler = urllib.request.ProxyHeadler(
	{"http":"http://" + proxy_id,
	  "https":"https://" + proxy_id}
	  )
opener = urllib,request.build_opener(proxy_headler)
response = opener.open("http://www.baidu.com")
html = response.read().decode("utf-8")
print(html)

创建opener
  opener 可以看做是一个私人订制,但是这个opener是可以定制的,例如,给它定制特殊的headers,或者给它定制指定的代理IP。这里可以使用build_opener()函数创建一个属于我们自己私人定制的opener。这样就相当于此opener已经设置好代理了,接下来可以直接调用opener对象的open() 方法,即可访问我们所想要的链接。

opener = urllib.request.build_opener(proxy_headler)

此处不能使用urlopen()函数打开网页,需要使用open()函数打开网页才可。

  下面代码实例使用IP池,每一次访问随机选取IP代理,假设我们的代理IP全部记录在IP.txt文件内。

from urllib import request, error
import random
import socket

url = "http://ip.tool.chinaz.com"
proxy_iplist = []

with open("IP.txt", "w") as f:
	for line in f.readlines():
		ip = line.strip()
		proxy_iplist.append(ip)

while True:
	proxy_ip = random.choice(proxy_iplist)
	proxy_headler = request.ProxyHeadler(
		{
			"http":"http://" + proxy_ip,
			"https":"https://" + proxy_ip
		})
	opener = request.build_opener(proxy_headler)
	try:
		response = opener.open(url, timeout = 1)
		print(response.read().decode("utf-8"))
	except error.URLError as e1:
		if isinstance(e1.reason, socket.timeout):
			print("TIME OUT!")
	except error.HTTPError as e2:
		if response.status == 404:
			print("404 ERROE!")
	finally:
		flag = input("Y/N")
		if flag == 'N' or flag == 'n':
			break

  遇到需要认证的代理

proxy = 'username:password@58.240.53.196:8080'

  这里只需要改变proxy变量,只需要加入代理认证的用户名密码即可。

Cookie
  我们调用http.cookiejar库的函数对日志进行操作。
  CookieJar类有一些子类,分别是FileCookieJar,MozillaCookieJar,LWPCookieJar。

  • CookieJar: 管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。

  • FileCookieJar (filename,delayload=None,policy=None): 从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。

  • MozillaCookieJar (filename,delayload=None,policy=None): 从FileCookieJar派生而来,创建与Mozilla浏览器 cookies.txt兼容的FileCookieJar实例。

  • LWPCookieJar (filename,delayload=None,policy=None): 从FileCookieJar派生而来,创建与libwww-perl标准的 Set-Cookie3 文件格式兼容的FileCookieJar实例。

代码实例

# 此段代码演示获取cookie,保存到cookiejar对象中并打印
#===============================================================================================================================================

import urllib.request
import http.cookiejar

url = "http://www.baidu.com"

cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open(url)

# 打印cookie
for item in cookie:
    print(item.name + "=" + item.value)
BAIDUID=069F91E0E5A0B7E85F7FDFE97194CA18:FG=1
BIDUPSID=069F91E0E5A0B7E87C083ED4D88287F6
H_PS_PSSID=35105_31660_34584_35490_35245_35796_35316_26350_35765_35746
PSTM=1644458154
BDSVRTM=0
BD_HOME=1
# 把获得的cookie保存到cookie.txt文件中
#===============================================================================================================================================
# 无load方法

import urllib.request
import http.cookiejar

url = "http://www.baidu.com"
filename = "cookie.txt"

cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open(url)
cookie.save()
# 把获得的cookie保存到cookie.txt文件中
#===============================================================================================================================================
# 有load方法
import urllib.request
import http.cookiejar

url = "http://www.baidu.com"
filename = "cookie.txt"

cookie = http.cookiejar.MozillaCookieJar()
cookie.load(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open(url)

cookie.txt文件:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file!  Do not edit.

.baidu.com	TRUE	/	FALSE	1675995432	BAIDUID	139CA77B6F46CA597186A3F1F6FCF790:FG=1
.baidu.com	TRUE	/	FALSE	3791943079	BIDUPSID	139CA77B6F46CA5980C5AB053579F5CF
.baidu.com	TRUE	/	FALSE	3791943079	PSTM	1644459432

urllib.error

  urllib.error 模块为 urllib.request 所引发的异常定义了异常类,基础异常类是 URLError。urllib.error 包含了两个方法,URLError 和 HTTPError。

  URLError 是 OSError 的一个子类,用于处理程序在遇到问题时会引发此异常(或其派生的异常),包含的属性 reason 为引发异常的原因。

  HTTPError 是 URLError 的一个子类,用于处理特殊 HTTP 错误例如作为认证请求的时候,包含的属性 code 为 HTTP 的状态码, reason 为引发异常的原因,headers 为导致 HTTPError 的特定 HTTP 请求的 HTTP 响应头。

对不存在的网页抓取并处理异常:

import urllib.request
import urllib.error

try:
	response = urllib.request.urlopen("http://www.baidu.com")
except urllib.error.HTTPError as e:
	if(e.code == 404)		
		print(response.getcode())		# 404

urllib.parse

  urllib.parse 用于解析 URL,格式如下:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
urlstring 为 字符串的 url 地址
scheme 为协议类型,
allow_fragments 参数为 false,则无法识别片段标识符。相反,它们被解析为路径,参数或查询组件的一部分,并 fragment 在返回值中设置为空字符串。

注意: 当urlstring里表明了协议类型时,scheme参数无效,协议以urlstring里注明的协议为准,若urlstring无协议,则以scheme协议为主

import urllib.parse

result1 =urllib.parse.urlparse("https://www.csdn.net/?spm=1001.2101.3001.4476")
result2 = urllib.parse.urlparse("www.csdn.net/?spm=1001.2101.3001.4476",scheme = "https")
result3 = urllib.parse.urlparse("https://www.csdn.net/?spm=1001.2101.3001.4476", scheme="http")

print(result1)
print(result2)
print(result3)

ParseResult(scheme='https', netloc='www.csdn.net', path='/', params='', query='spm=1001.2101.3001.4476', fragment='')
ParseResult(scheme='https', netloc='', path='www.csdn.net/', params='', query='spm=1001.2101.3001.4476', fragment='')
ParseResult(scheme='https', netloc='www.csdn.net', path='/', params='', query='spm=1001.2101.3001.4476', fragment='')

  从结果可以看出,内容是一个元组,包含 6 个字符串:协议,位置,路径,参数,查询,判断。

  我们也可以直接读取属性

from urllib.parse import urlparse

result = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(result.scheme)
https
属性索引值(如果不存在)
scheme0URL协议scheme参数
netloc1网络位置部分空字符串
path2分层路径空字符串
paramg3最后路径元素的参数空字符串
query4查询组件空字符串
fragment5片段识别空字符串
username用户名None
password密码None
hostname主机名(小写)None
port端口号为整数(如果存在)None

urlunparse
  除此之外,我们还可以用urlunparse进行反拼接

from urllib.parse import urlunparse

data = ["http", "www.baidu.com", "index.html", "user", "a=6", "comment"]
print(urlunparse(data))


http://www.baidu.com/index.html;user?a=6#comment

urljoin

urljoin(base, url, allow_fragments=True)
base 基准母站
url 需要拼接成的绝对路径的url
allow_fragments 是否识别片段标识符

  urljoin()将base和url拼接成一个网址,如果url是一个完整的网址,则以url为基准

from urllib import parse

url1 = parse.urljoin("https://www.baidu.com", "index.html")
url2 = parse.urljoin("https://www.baidu.com", "https://www.jianshu.com/p/20065f9b39bb")

print(url1)
print(url2)



https://www.baidu.com/index.html
https://www.jianshu.com/p/20065f9b39bb

urlencode
  我们知道GET传递参数的时候用“&”符号间隔,然而Python中字典元素之间却用“,”间隔,我们可以用urlencode将字典转化为用“&”间隔的键值对进行传参

from urllib import parse

data = {
    "keyword":"Python",
    "id":"3252525",
    "page":"3"
}

base_url = "http://www.example.com"
url = base_url + parse.urlencode(data)
print(url)



http://www.example.comkeyword=Python&id=3252525&page=3

urllib.robotparser

  urllib.robotparser 用于解析 robots.txt 文件。

  robots.txt(统一小写)是一种存放于网站根目录下的 robots 协议,它通常用于告诉搜索引擎对网站的抓取规则。

urllib.robotparser 提供了 RobotFileParser 类,语法如下:

class urllib.robotparser.RobotFileParser(url='')

这个类提供了一些可以读取、解析 robots.txt 文件的方法:

  • set_url(url) - 设置 robots.txt 文件的 URL。

  • read() - 读取 robots.txt URL 并将其输入解析器。

  • parse(lines) - 解析行参数。

  • can_fetch(useragent, url) - 如果允许 useragent 按照被解析 robots.txt 文件中的规则来获取 url 则返回 True。

  • mtime() -返回最近一次获取 robots.txt 文件的时间。 这适用于需要定期检查 robots.txt 文件更新情况的长时间运行的网页爬虫。

  • modified() - 将最近一次获取 robots.txt 文件的时间设置为当前时间。

  • crawl_delay(useragent) -为指定的 useragent 从 robots.txt 返回 Crawl-delay 形参。 如果此形参不存在或不适用于指定的 useragent 或者此形参的 robots.txt 条目存在语法错误,则返回 None。

  • request_rate(useragent) -以 named tuple RequestRate(requests, seconds) 的形式从 robots.txt 返回 Request-rate 形参的内容。 如果此形参不存在或不适用于指定的 useragent 或者此形参的 robots.txt 条目存在语法错误,则返回 None。

  • site_maps() - 以 list() 的形式从 robots.txt 返回 Sitemap 形参的内容。 如果此形参不存在或者此形参的 robots.txt 条目存在语法错误,则返回 None。

>>> import urllib.robotparser
>>> rp = urllib.robotparser.RobotFileParser()
>>> rp.set_url("http://www.musi-cal.com/robots.txt")
>>> rp.read()
>>> rrate = rp.request_rate("*")
>>> rrate.requests
3
>>> rrate.seconds
20
>>> rp.crawl_delay("*")
6
>>> rp.can_fetch("*", "http://www.musi-cal.com/cgi-bin/search?city=San+Francisco")
False
>>> rp.can_fetch("*", "http://www.musi-cal.com/")
True
  • 6
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值