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)

 结果如下:

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

(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'))

 结果如下

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)

http://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8

(10)unquote()

对url进行解码

from urllib.parse import unquote

url = 'http://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))

http://www.baidu.com/s?wd=壁纸

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的主要内容,如果未能解决你的问题,请参考以下文章

python爬虫学习记录基本库的使用——正则表达式

python3网络爬虫学习——基本库的使用

python3网络爬虫学习——基本库的使用

python爬虫学习记录解析库的使用——pyquery

python3网络爬虫学习——基本库的使用

python爬虫_urllib2库的基本使用