python爬虫学习记录基本库的使用——urllib
Posted 玛卡巴卡巴巴亚卡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python爬虫学习记录基本库的使用——urllib相关的知识,希望对你有一定的参考价值。
一、使用urllib库
python内置HTTP请求库,包含如下四个模块:
request:模拟发送请求
error:异常处理模块
parse:工具模块,提供url处理方法
robotparser:识别网站robots.txt文件,判断哪些网站可爬取
1、发送请求
(1)urlopen()
模拟浏览器请求发起过程
如下代码可以爬取python官网源代码
from urllib import request
url = 'https://www.python.org'
response = request.urlopen(url)
print(response.read().decode('utf-8'))
使用
print(type(response))
可以得到<class 'http.client.HTTPResponse'>,主要包含read(),readinto(),getheader(name),getheaders(),fileno()等方法,以及msg,version,status,debuglevel,closed等属性。
urlopen参数API如下:
urllib.request.urlopen(url,data=None,[timeout,*],cafile=None,capath=None,cadefault=False,context=None)
如下代码,传递一个word,参数是hello,转码成bytes类型。用urllib中的parse的urlencode方法把参数字典转化成字符串,指定参数编码格式是utf-8,结果如下
b'{\\n "args": {}, \\n "data": "", \\n "files": {}, \\n "form": {\\n "word": "hello"\\n }, \\n "headers": {\\n "Accept-Encoding": "identity", \\n "Content-Length": "10", \\n "Content-Type": "application/x-www-form-urlencoded", \\n "Host": "httpbin.org", \\n "User-Agent": "Python-urllib/3.8", \\n "X-Amzn-Trace-Id": "Root=1-60e9acb1-65e3b6fe248bdd517eccab46"\\n }, \\n "json": null, \\n "origin": "125.68.93.64", \\n "url": "http://httpbin.org/post"\\n}\\n'
(2)request
urlopen可以实现最基本的请求发起,但是如果请求中需要加入header等信息,需要使用request请求方法。
request.Request(url,data=None,headers={ }, origin_req_host=None, unverifiable=False, method=None)
url:请求url,必传参数
data:如要传递,必须传递bytes字节流类型,如果是字典,可以使用urllib.parse模块中的urlencode编码
headers:一个字点,请求头,可通过headers直接构造,也可以通过请求实例的add_header()方法添加
origin_req_host:请求方的host名称或者IP地址
unverifiable:请求是否无法验证
method:请求使用方法,post、get、put
代码如下:
from urllib import request
from urllib import parse
url = 'http://httpbin.org/post'
dic = {'word':'hello!'}
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Host': 'httpbin.org'
}
data = bytes(parse.urlencode(dic), encoding='utf-8')
resp = request.Request(url,data=data,headers=headers,method='POST')
response = request.urlopen(resp)
print(response.read())
结果如下:
b'{\\n "args": {}, \\n "data": "", \\n "files": {}, \\n "form": {\\n "word": "hello!"\\n }, \\n "headers": {\\n "Accept-Encoding": "identity", \\n "Content-Length": "13", \\n "Content-Type": "application/x-www-form-urlencoded", \\n "Host": "httpbin.org", \\n "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", \\n "X-Amzn-Trace-Id": "Root=1-60e9b2a0-13ea12d9308d4b33201499cc"\\n }, \\n "json": null, \\n "origin": "125.68.93.64", \\n "url": "http://httpbin.org/post"\\n}\\n'
(3)高级用法
可以用来处理cookie,设置代理——Handler
urllib.request模块中有一个BaseHandler类,是所有其他Handler的父类。提供了最基本的方法,如default_open(),protocol_request()等。
Handler子类继承BaseHandler这个类,
HTTPDefaultErrorHandler:处理HTTP响应错误,抛出HTTPError类型异常
HTTPRedirectHandler:处理重定向
HTTPCookieProcessor:处理cookie
ProxyHandler:设置代理,默认为空
HTTPBasicAuthHandler:管理认证,如链接打开需要认证时,可以解决认证问题
还有一个重要的类是OpenerDirector,简称Opener。可以利用Handler来建立Opener。
实例:
(1)获取网站cookie
import http.cookiejar,urllib.request
url = 'http://www.baidu.com'
#声明CookieJar对象
cookie = http.cookiejar.CookieJar()
#创建Hndler
handler = urllib.request.HTTPCookieProcessor(cookie)
#build_opener()创建opner
opener = urllib.request.build_opener(handler)
response = opener.open(url)
for item in cookie:
print(item.name+':'+item.value)
读取cookie内容如下:
BAIDUID:B87E588267CBCA6FEB3B631C1998B984:FG=1
BIDUPSID:B87E588267CBCA6FDF9EAFFBB52CAD0B
H_PS_PSSID:34100_34224_31253_34004_34133_34073_34106_26350_34245
PSTM:1625929492
BDSVRTM:0
如需要把cookie保存在文件中,则需要MozillaCookieJar,,可以处理cookie文件相关的事件
'''
cookie保存在文件中
'''
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(ignore_discard=True, ignore_expires=True)
#ignore_discard:即使cookies将被丢弃也将它保存下来
#ignore_expires:如果cookies已经过期也将它保存并且文件已存在时将覆盖
生成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 1657356433 BAIDUID 0DA1463181F0715F3FCE1CC177AE49C7:FG=1 .baidu.com TRUE / FALSE 3773304080 BIDUPSID 0DA1463181F0715F5A6F70048008DD65 .baidu.com TRUE / FALSE H_PS_PSSID 33802_34222_31660_33848_34244 .baidu.com TRUE / FALSE 3773304080 PSTM 1625820433 www.baidu.com FALSE / FALSE BDSVRTM 0 www.baidu.com FALSE / FALSE BD_HOME 1
也可以使用LWPCookieJar读取和保存cookie,但格式与MozillaCookieJar不同,如果需要保存成LWP格式的cookie文件,在声明时就修改成:
cookie = http.cookiejar.LWPCookieJar(filename)
'''
从文件中读取cookie
'''
cookie = http.cookiejar.MozillaCookieJar()
cookie.load('cookie.txt')
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open(url)
print(response.read().decode('utf-8'))
2、处理异常
(1)URLError
来自urllib库中的error模块,由request模块生的异常都可以通过捕获这个类来处理。
它具有一个熟悉你跟reason,返回错误原因
from urllib import request,error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.URLError as e:
print(e.reason)
返回结果如下
H:\\python_file\\Scripts\\python.exe H:/python_file/3.py
Not Found
(2)HTTPError
是URLError的子类,处理HTTP请求错误。
有三个属性:
code:返回HTTP状态码
reason:返回错误原因
headers:返回请求头
from urllib import request,error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
print(e.reason,e.code, e.headers)
Not Found 404 Server: GitHub.com
Date: Sat, 10 Jul 2021 15:21:26 GMT
Content-Type: text/html; charset=utf-8
X-NWS-UUID-VERIFY: ce6d3a60300dcdec36f851b251033595
Access-Control-Allow-Origin: *
ETag: "60e016f4-cd89"
x-proxy-cache: MISS
X-GitHub-Request-Id: 6D48:7F6D:D3E37A:E146BD:60E9BAF6
Accept-Ranges: bytes
Age: 0
Via: 1.1 varnish
X-Served-By: cache-nrt18320-NRT
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1625930486.044167,VS0,VE153
Vary: Accept-Encoding
X-Fastly-Request-ID: e0ca14d433d9e8454cdec2cc2f4177e7be3f367e
X-Daa-Tunnel: hop_count=2
X-Cache-Lookup: Hit From Upstream
X-Cache-Lookup: Hit From Inner Cluster
Content-Length: 52617
X-NWS-LOG-UUID: 10733046919308363998
Connection: close
X-Cache-Lookup: Cache Miss
由于URLError是HTTPError的父类,可以选择捕获子类的错误,再去捕获父类的错误。
from urllib import request,error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
print(e.reason,e.code, e.headers)
except error.URLError as e:
print(e.reason)
else:
print('Request Successfully')
reason属性也可以返回一个对象:
from urllib import request, error
import socket
url = 'http://www.baidu.com'
try:
response = request.urlopen(url, timeout=0.01)
except error.URLError as e:
print(type(e.reason))
if isinstance(e.reason, socket.timeout):
#isinstance判断类型,,前后一样,返回true
print('TIME OUT')
3、解析链接
urllib库中的parse模块,定义了处理URL的标准接口,可以实现各部分的抽取合并以及链接转换。
(1)urlparse()
可以识别和拆解url
from urllib.parse import urlparse
url = 'http://www.baidu.com/index.html;user?id=5=comment'
result = urlparse(url)
print(type(result),result,sep='\\n')
<class 'urllib.parse.ParseResult'>
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5=comment', fragment='')
可以看出类型是ParseResult,结果有六个部分,scheme是协议,netloc是域名,path是访问路径,parse是参数,?后是查找条件query,#后是锚点。ParseResult是一个元组,可以利用所以顺序获取,如result[0],result[1],或者使用属性名获取,如result.netloc,result.scheme
urlparse的api用法如下:
urllib.parse.urlparse(urlstring, scheme=' ', allow_fragments=True)
allow_fragments为是否忽略fragment,如设置成false,则忽略fragment部分,当url不包含parems和query时,fragemnt就会被解析为path的一部分。
(2)urlunparse()
构造url,需要用列表类型,长度必须是6
from urllib.parse import urlunparse
data = ['http','www.baidu.com','index.html','user','a=6','comment']
result = urlunparse(data)
print(result)
结果如下:
http://www.baidu.com/index.html;user?a=6#comment
(3)urlsplit()
与urlparse类似我,但不再单独解析params部分,只返回5个结果。把params合并到path中:
from urllib.parse import urlsplit
url = 'http://www.baidu.com/index.html;user?id=5=comment'
result = urlsplit(url)
print(result)
结果如下:
SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5=comment', fragment='')
因为返回结果是SplitResult类型,也是一个元组类型,可以通过属性或索引获取。
result.scheme或result[0]
(4)urlunsplit()
与urlunparse类似,唯一的区别是传入长度只能是5
from urllib.parse import urlunsplit
data = ['http','www.baidu.com','index.html','a=6','comment']
result = urlunsplit(data)
print(result)
结果如下:
(5)urljoin()
完成连接合并,提供一个base_url作为第一个参数,新链接作为第二个参数。把base_url的scheme,netloc,path分析,然后后对新链接缺失部分进行补充。如果这三项在base_url中不存在,就不充,存在就是用新的链接部分
from urllib.parse import urljoin
print(urljoin('http://www.baidu.com','https://cuiqingcai.com/FAQ.html'))
结果如下
(6)urlencode()
构造GET请求参数。
这里先声明了一个字典,把参数表示出啦,调用urlencode()方法把其序列化成GET请求参数
from urllib.parse import urlencode
params = {
'name' : 'alice',
'age' : '22'
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)
结果如下
http://www.baidu.com?name=alice&age=22
(7)parse_qs()
对GET请求参数反序列化
from urllib.parse import parse_qs
parse = 'name=alice&age=22'
print(parse_qs(parse))
结果如下:
{'name': ['alice'], 'age': ['22']}
(8)parse_qsl()
GET参数化成元组组成列表
from urllib.parse import parse_qsl
parse = 'name=alice&age=22'
print(parse_qsl(parse))
结果如下:
[('name', 'alice'), ('age', '22')]
(9)quote()
将内容转化成url编码格式,可以把中文字符转化成url编码
from urllib.parse import quote
keyword = '壁纸'
base_url = 'http://www.baidu.com/s?wd='
url = base_url + quote(keyword)
print(url)
(10)unquote()
对url进行解码
from urllib.parse import unquote
url = 'http://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))
4、分析Robot协议
利用urllib的robotparser模块,可以实现网站robots协议的分析。
(1)Robots协议
告诉爬虫和搜索引擎哪些页面可以抓取。通常放在网站根目录下一个robots.txt文本中。百度的robots.txt如下。
User-agent: Baiduspider
Disallow: /baidu
Disallow: /s?
Disallow: /ulink?
Disallow: /link?
Disallow: /home/news/data/
Disallow: /bh
user-agent是搜索爬虫的名称,设置成*表示该协议对任何爬虫有效。
disallow是不允许抓取的目录。/表示不允许抓取所有页面。
(2)robotparser
该模块提供了一个RobotFileParser,可以根据某网站的robots.txt文件来判断一个爬取爬虫是否有权限爬取这个网页。只需要在构造方法中传入robots.txt链接。
声明:urllib.robotsparser.RobotFileParser(url=' ')
也可以声明时不传入,默认为空,最后用set_url()方法设置。
set_url():设置robots.txt文件链接
read():读取robots.txt并分析。这个方法执行一个读取和分析操作,不调用的话之后的所有判断都是false。
parse():解析robots.txt文件,传入参数是robots.txt某些行的内容,按照robots语法解析
can_fetch():第一个参数user-agent,另一个是要抓取的url。判断搜索引擎是否可以抓取这个url。
mtime():返回上次抓取和分析robots.txt的时间,可以定期检查新的robots
modified():把当前时间设置成上次抓取和分析robots.txt的时间
from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url('http://www.jianshu.com/robots.txt')
rp.read()
print(rp.can_fetch('*','http://www.jianshu.com/p/b67554025d7d'))
返回结果如下
False
也可以使用parse()方法进行读取和分析
以上是关于python爬虫学习记录基本库的使用——urllib的主要内容,如果未能解决你的问题,请参考以下文章