目录
urllib库是python自带的内置库,不需要安装
urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据
在Python3的urllib库中,所有和网络请求相关的方法,都被集到urllib.request模块中
request中常用的方法
urlopen函数用来创建一个表示远程url的类文件对象,然后像本地文件一样操作这个类文件对象来获取远程数据
部分源码
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
*, cafile=None, capath=None, cadefault=False, context=None):
'''Open the URL url, which can be either a string or a Request object.
*data* must be an object specifying additional data to be sent to
the server, or None if no such data is needed. See Request for
details.
'''
参数详解
句柄如何理解?
数值上,是一个32位无符号整型值(32位系统下);逻辑上,相当于指针的指针;形象理解上,是Windows中各个对象的一个唯一的、固定不变的ID;作用上,Windows使用句柄来标识诸如窗口、位图、画笔等对象,并通过句柄找到这些对象
from urllib import request
'''
Open the URL url, which can be either a string or a Request object
'''
resp = request.urlopen('https://www.sogou.com/')
print(resp) # 返回一个HTTPresponse对象,<http.client.HTTPResponse object at 0x000002E0CADA0C50>
print(resp.read()) # 返回网页源代码
print(resp.read(1024)) # 返回1024字节大小的数据
print(resp.readline()) # 返回一行数据
print(resp.readlines()) # 返回多行数据
print(resp.getcode()) # 返回状态码:200
这个函数可以方便的将网页上的一个文件保存到本地。以下代码可以非常方便的将搜狗的首页下载到本地:
from urllib import request
request.urlretrieve('https://www.sogou.com/','sogou.html')
部分源码
def urlretrieve(url, filename=None, reporthook=None, data=None):
"""
Retrieve a URL into a temporary location on disk.
Requires a URL argument. If a filename is passed, it is used as
the temporary file location. The reporthook argument should be
a callable that accepts a block number, a read size, and the
total file size of the URL target. The data argument should be
valid URL encoded data.
If a filename is passed and the URL points to a local resource,
the result is a copy from local file to new file.
Returns a tuple containing the path to the newly created
data file as well as the resulting HTTPMessage object.
"""
格式
request.urlretrieve(url,文件名)
示例
from urllib import request
request.urlretrieve('https://th.bing.com/th/id/OIP.NX9KpjV4Mk_e72YV_6nPNgDhEs?w=182&h=243&c=7&r=0&o=5&dpr=1.25&pid=1.7','haizei.jpg')
urlencode可以把字典数据转换为URL编码的数据,如果我们使用浏览器发送一个请求的时候,url中携带汉字,那么浏览器就会自动进行了url编码
如何解码?使用parse_qs函数就可以解码了
部分源码
def urlencode(query, doseq=False, safe='', encoding=None, errors=None,
quote_via=quote_plus):
'''Encode a dict or sequence of two-element tuples into a URL query string.'''
def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
encoding='utf-8', errors='replace', max_num_fields=None):
'''Parse a query given as a string argument.'''
示例1
from urllib import parse
data = {'name': 'Hammer', 'age': 18}
# 编码
res = parse.urlencode(data)
print(res) # name=Hammer&age=18
# 解码
ret = parse.parse_qs(res)
print(ret) # {'name': ['Hammer'], 'age': ['18']}
示例2
浏览器会帮助我们进行url编码,那么我们使用pycharm进行爬取数据的时候,中文需要我们自己处理
from urllib import parse,request
data1 = {'q':'古力娜扎'}
res1 = parse.urlencode(data1)
print(res1,type(res1)) # q=%E5%8F%A4%E5%8A%9B%E5%A8%9C%E6%89%8E <class 'str'>
res = request.urlopen('https://www.bing.com/search?'+res1)
print(res.read())
示例3
这里需要注意的是,url字符串编码和encode方法编码的结果是不一样的
data = {'Name':'古力娜扎'}
res2 = parse.urlencode(data)
print(res2) # Name=%E5%8F%A4%E5%8A%9B%E5%A8%9C%E6%89%8E
qs = parse.quote('古力娜扎')
print(qs) # %E5%8F%A4%E5%8A%9B%E5%A8%9C%E6%89%8E
print('古力娜扎'.encode('utf8')) # b'\xe5\x8f\xa4\xe5\x8a\x9b\xe5\xa8\x9c\xe6\x89\x8e'
有时候拿到一个url,想要对这个url的各个组成部分进行分割,那么这个时候使用urlparse或者urlsplit来进行分割;
URL组成:
:
作为分隔符,不写的时候使用端口,比如127.0.0.1:8000“?”
,则是从域名后的最后一个“/”开始到“#”
为止,是文件部分,如果没有“?”
和“#”
,那么从域名后的最后一个“/”
开始到结束,都是文件名部分。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名?
开始到#
为止之间的部分为有参部分,又称为搜索部分或者查询部分,参数允许有多个,一般用&
做分隔符部分源码
# urlsplit函数
def urlsplit(url, scheme='', allow_fragments=True):
'''
Parse a URL into 5 components:
<scheme>://<netloc>/<path>?<query>#<fragment>
Return a 5-tuple: (scheme, netloc, path, query, fragment).
'''
# urlparse函数
def urlparse(url, scheme='', allow_fragments=True):
"""Parse a URL into 6 components:
<scheme>://<netloc>/<path>;<params>?<query>#<fragment>
Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
Note that we don't break the components up in smaller bits
(e.g. netloc is a single string) and we don't expand % escapes."""
注意
通过源码注释的对比,我们发现urlparse返回的参数比urlsplit返回的参数多一个params
,params是url中的可选参数
示例
from urllib import parse
res = parse.urlparse('https://zzk.cnblogs.com/my/s/blogpost-p?Keywords=python')
ret = parse.urlsplit('https://zzk.cnblogs.com/my/s/blogpost-p?Keywords=python')
print(res,type(res))
print(ret,type(ret))
'''
结果:
ParseResult(scheme='https', netloc='zzk.cnblogs.com', path='/my/s/blogpost-p', params='', query='Keywords=python', fragment='') <class 'urllib.parse.ParseResult'>
SplitResult(scheme='https', netloc='zzk.cnblogs.com', path='/my/s/blogpost-p', query='Keywords=python', fragment='') <class 'urllib.parse.SplitResult'>
'''
# 返回的是一个对象,那么可以通过点的方法获取到该对象的属性值
print(res.scheme,res.params)
Request类也是用于处理网络请求,如果想要在请求的时候增加一些请求头,那么就必须使用request.Request类来实现,比如要增加一个User-Agent
部分源码:
class Request:
def __init__(self, url, data=None, headers={},
origin_req_host=None, unverifiable=False,
method=None):
通过源码我们可以看到,必传的参数有url和headers(传字典)
from urllib import request
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39'
}
res = request.Request('https://www.cnblogs.com/',headers=header)
print(res) # <urllib.request.Request object at 0x000001959F347CF8>
ret = request.urlopen(res)
print(ret.read()) # 返回网页源代码
我们可以通过添加UA来获取更多的网页源代码··
from urllib import request
import json
url = 'https://piaofang.maoyan.com/dashboard-ajax?orderType=0&uuid=7cba1a83-0143-4e91-b431-6e48cf2c4f57&timeStamp=1647662149259&User-Agent=TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzk5LjAuNDg0NC41MSBTYWZhcmkvNTM3LjM2IEVkZy85OS4wLjExNTAuMzk%3D&index=442&channelId=40009&sVersion=2&signKey=fb7aa416ff3c852bfe69b01ee7952272'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39'
}
ret = request.Request(url,headers=header)
resp = request.urlopen(ret)
# print(resp.get('movieList').get('data').get('list').decode('utf8'))
data = resp.read().decode('utf8')
'''注意这里获取的是json格式数据'''
data = json.loads(data)
data_list = data.get('movieList').get('data').get('list')
for line in data_list:
print(line.get('movieInfo'))
'''结果'''
{'movieId': 341955, 'movieName': '新蝙蝠侠', 'releaseInfo': '上映2天'}
{'movieId': 338380, 'movieName': '神秘海域', 'releaseInfo': '上映6天'}
{'movieId': 1446115, 'movieName': '长津湖之水门桥', 'releaseInfo': '上映47天'}
{'movieId': 1405863, 'movieName': '熊出没·重返地球', 'releaseInfo': '上映47天'}
{'movieId': 1433696, 'movieName': '这个杀手不太冷静', 'releaseInfo': '上映47天'}
{'movieId': 1300821, 'movieName': '花束般的恋爱', 'releaseInfo': '上映26天'}
{'movieId': 1383307, 'movieName': '奇迹·笨小孩', 'releaseInfo': '上映47天'}
{'movieId': 1435147, 'movieName': '我们的冬奥', 'releaseInfo': '上映29天'}
{'movieId': 1309268, 'movieName': '可不可以你也刚好喜欢我', 'releaseInfo': '上映9天'}
{'movieId': 1265626, 'movieName': '印度女孩', 'releaseInfo': '上映2天'}
{'movieId': 1367251, 'movieName': '狙击手', 'releaseInfo': '上映47天'}
{'movieId': 1445469, 'movieName': '喜羊羊与灰太狼之筐出未来', 'releaseInfo': '上映47天'}
{'movieId': 1303796, 'movieName': '“炼”爱', 'releaseInfo': '上映2天'}
{'movieId': 1405621, 'movieName': '玛纳斯人之失落的秘境', 'releaseInfo': '上映首日'}
{'movieId': 1214749, 'movieName': '纽约的一个雨天', 'releaseInfo': '上映23天'}
{'movieId': 1302341, 'movieName': '*小道', 'releaseInfo': ''}
{'movieId': 1247341, 'movieName': '妖怪手表:永远的朋友', 'releaseInfo': '上映8天'}
{'movieId': 1396517, 'movieName': '年少有你', 'releaseInfo': '上映2天'}
{'movieId': 1338396, 'movieName': '如果有一天我将会离开你', 'releaseInfo': '上映9天'}
from urllib import request,parse
for page in range(9270,9273):
header = {
'user - agent': 'Mozilla / 5.0(Windows NT 10.0;Win64; x64) AppleWebKit /537.36KHTML, likeGecko) Chrome/99.0.4844.51 Safari / 537.36 Edg / 99.0.1150.39'
}
url = f'https://www.biedoul.com/index/{page}/'
request.Request(url=url,headers=header)
res = request.urlopen(url)
request.urlretrieve(url,f'{page}.html')
page_data = res.read().decode('utf8')
print(page_data)
很多时候我们玩游戏开外挂,飞天遁地透视····最后被封号~我们爬虫也类似,老是不断的去请求,人家也会烦,封你的ip;
在我们爬取数据的时候如果对服务器请求的次数过多的时候,服务器也不傻会识别出来是非正常请求,一般采取我措施是封IP措施,这时候我们的IP就不能正常访问,可以通过“换小号继续玩”;
查看http请求的一些参数:http://httpbin.org
查看没有使用代理的ip地址:
http://httpbin.org/ip
from urllib import request
# No Proxy
url = 'http://httpbin.org/ip'
resp = request.urlopen(url)
print(resp.read()) # b'{\n "origin": "112.64.68.252"\n}\n'
设置代理ip
通过设置代理ip解决封ip问题,原理是通过请求代理服务器,然后通过代理服务器请求目标服务器,然后返回数据
常用的代理有:
西刺免费代理IP:http://www.xicidaili.com/
from urllib import request
url = 'http://httpbin.org/ip'
handler = request.ProxyHandler({'http':'106.15.197.250:8001'})
opener = request.build_opener(handler)
resp = opener.open(url)
print(resp.read()) # b'{\n "origin": "106.15.197.250"\n}\n'
'''我们可以看到ip并不是以前的ip了,这样就设置成功了,但是缺点就是免费的不稳定'''
指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据,cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据;
我们知道HTTP的四大特征:
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH; Domain=DOMAIN_NAME;SECURE
参数意义:
from urllib import request
url = 'https://www.zhihu.com/hot'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
'cookie': '_zap=8812b5e0-0b83-4ce1-9ac5-c913debd77c5; d_c0="AIDel4RQJxSPTp9hk0DqVuFjlrklYMgxsHM=|1639015736"; _9755xjdesxxd_=32; YD00517437729195%3AWM_TID=cfvcktVDh9REFEQRAVJ%2B97fYipUcBdd5; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1642496751,1642507682,1642515429,1642954789; _xsrf=3S5Nqf0sEQkI3Cln9pmAI6lgYnk6Wxoh; __snaker__id=IKbmra7CqY74Sn2D; YD00517437729195%3AWM_NI=utbfMp3td5HSlvkH%2FYeFIlzsYQABzUsxftqGf3FISbVKXYoqU0oCNKXIYIGU4%2Bb1V3MvuX1jFJyMVSE8dQ2rCDro8DGNd1ZNcs%2BOCpPc8OSf67cfOoqOnWaAR%2B3MfelJdkU%3D; YD00517437729195%3AWM_NIKE=9ca17ae2e6ffcda170e2e6ee9aae429789fa90e44083b08ab7c55e828b9aaaf87efba899a9ef658ca681d2fb2af0fea7c3b92ab7acae87d07cf1acacd6cb59b0aaa5a9ae53a79a878df9799b8f8fa3f95fb1a8aa95f44da6ed8aaad26a969598baee7b97f0a1a4cd419c9797aac65ff8f5aed2d5398faabbb9b4628696b7aed55987e8acb2b17a819cbe90bb508592acd2d946a1ade5b0c27c94bdf8b0d26ef6e9ad87ce65b391a2b8e44b92f5fdaee56fb096ac8cd837e2a3; gdxidpyhxdE=V9Pnc%5CLTb2HTGVfNr3WCQW%2FW%5CCPZOK0XnGxAObaD1RC8G7lwZLG5UoGtylAs8UsXb6no7b1wQyxAg%2FPw1xBoaf%2BUulfG9%2BxkiQ0JwMdYZodeVJ6V1lpw1YfGScmJnPoMVyVrarJ%5CzZja6%2FMUjsb4IjY1wB2gyVrmaOoSKxvHeJfUiKGZ%3A1647680377803; captcha_session_v2=2|1:0|10:1647679931|18:captcha_session_v2|88:RlMvRkdSRUU4dCtjMnlPRmVnN2JjQ2EzeCtJT3p1YkViREM2L3R1TlByMXdna0RRRWpiSWVwMUd6cWFxa2dKdQ==|b723dce9ca2e90df4737d71cbe58ceb6006083307013e7b44c5557d89ec4ff2f; captcha_ticket_v2=2|1:0|10:1647679942|17:captcha_ticket_v2|704:eyJ2YWxpZGF0ZSI6IkNOMzFfUHZ1dGhpeHdVa3VCcGM3S3Z4MDBwcGVDd2ZLV0dLVWtCQVRpZlFuUGNQZi15U3hZMnJQMkQxYlE0ZTlYSzlrTTdzTnVuaXZySjZyb3RYcnlwa0hUODhVbFFzU1poT0NIR0FVYU56YlJPc3lEYzlGbldQbFp2VGRVTXBMX3J4djVVbUhtd1VWRGI4MFB1QUhyVUxWUzhDVGpYN1lHaHBYRDBJQndwcVZUZDFsUWVqTXFWUHE0MnFicGhGSEFQZFVsb0dXd1FYd3g3X21VekdUd0ZUWllhNUtoam9vT1NwMHQxUUxzWEZXZmN2d0N0Y3NLamxvZ244LTRxd2t2Zk41WVZpc3dlOVJKUkwyZ21vNWFBcy03N0ZqbXFBZXNiRlpiRklIeC5ndnRkSUJlUi5CR2hQR05VQnMxWGRHUFh3aG11TGlrdEVhbnNoR1dzN2RLZXVzWks1eG1zMXVSeXdqaGR4VW1GeEVIc1VNZ2xQMXU1NnNyVmxCWUdTSmFESlJHNU9zUnlDVG1mTHE3OW92MFdiV1lYQzRmdXFXOVVaMnlHLjRKWEFNQTZVeHh6cXBGcExjLWtWd1FKMG9UbG03OFVyYmlRMmFJeVg4emhJVkd4WU5uRnRmNmo4NFdjZG54SS5WQ1F6LXhjRWNuS21hNi1CVVJTcHVULXNwMyJ9|deb333726cc56b3900502d1c8ecd3dd1d91e56ba4090ee683a0af86c18986274; z_c0=2|1:0|10:1647679962|4:z_c0|92:Mi4xaGlpOEJBQUFBQUFBZ042WGhGQW5GQ1lBQUFCZ0FsVk4ydWNpWXdCUVpFSXBYM2JBWTdMSnFEUHZ6VnhIT01HZXd3|63b889aa3a6ee8c58b1e84d9a7de39bfa84a8b8c74f14775399c623f0d73f11a; q_c1=87cdf895ba3444b8bdf4fc2bf51766c2|1647679962000|1647679962000; NOT_UNREGISTER_WAITING=1; tst=h; '
}
hdr = request.Request(url, headers=headers)
resp = request.urlopen(hdr)
print(resp.read().decode('utf8'))
介于每次处理cookie比较麻烦还得从浏览器上copy过来使用,现在使用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实例;
from urllib import request
from urllib import parse
from http.cookiejar import CookieJar
#个人网页https://i.meishi.cc/cook.php?id=13686422
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
#1.登录
#1.1 创建cookiejar对象
cookiejar = CookieJar()
#1.2 使用cookiejar创建一个HTTPCookieProcess对象
handler = request.HTTPCookieProcessor(cookiejar)
#1.3 使用上一步的创建的handler创建一个opener
opener = request.build_opener(handler)
#1.4 使用opener发送登录请求 (账号和密码)
post_url = 'https://i.meishi.cc/login.php?redirect=https%3A%2F%2Fwww.meishij.net%2F'
post_data = parse.urlencode({
'username':'1097566154@qq.com',
'password':'wq15290884759.'
})
'''如果登录后发送的是GET请求,那么就不需要携带登录信息直接获取'''
req = request.Request(post_url,data=post_data.encode('utf-8'))
opener.open(req)
#2.访问个人网页
url = 'https://i.meishi.cc/cook.php?id=13686422'
rq = request.Request(url,headers=headers)
resp = opener.open(rq)
print(resp.read().decode('utf-8'))
from urllib import request
from http.cookiejar import MozillaCookieJar
# 保存
cookiejar = MozillaCookieJar('cookie.txt')
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)
resp = opener.open('https://www.baidu.com')
# resp = opener.open('http://www.httpbin.org/cookies/set/course/abc')
cookiejar.save(ignore_discard=True,ignore_expires=True)
# ignore_discard=True 即使cookies即将被丢弃也要保存下来
# ignore_expires=True 如果cookies已经过期也将它保存并且文件已存在时将覆盖
from urllib import request
from http.cookiejar import MozillaCookieJar
#加载
cookiejar = MozillaCookieJar('cookie.txt')
cookiejar.load()
for cookie in cookiejar:
print(cookie)
手机扫一扫
移动阅读更方便
你可能感兴趣的文章