系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、urllib库
- 1.1 urlopen函数
- 1.2 urlretrieve函数
- 1.3 urlencode函数
- 1.4 parse_qs函数
- 1.5 urlparse和urlsplit
- 1.6 request.Request类
- 1.7 测试:用Request爬取拉勾网数据
- 1.8 ProxyHandler处理器(代理设置)
- 二、cookie
- 2.1 什么是cookie
- 2.2 cookie的格式
- 2.3 使用cookielib库和HTTPCookieProcessor模拟登录
- 2.4 http.cookiejar模块
- 2.5 保存cookie到本地
- 2.6 从本地加载cookie
前言
一、urllib库
urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据。
1.1 urlopen函数
在Python3的urllib库中,所有和网络请求相关的方法,都被集到urllib.request模块下面了,以先来看下urlopen函数基本的使用:
from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())
print(resp.getcode())
实际上,使用浏览器访问百度,右键查看源代码。你会发现,跟我们刚才打印出来的数据是一模一样的。也就是说,上面的三行代码就已经帮我们把百度的首页的全部代码爬下来了。一个基本的url请求对应的python代码真的非常简单。
以下对urlopen函数的进行详细讲解:
-
url
:请求的url。 -
data
:请求的data,如果设置了这个值,那么将变成post请求。 -
返回值
:返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象。有read(size)、readline、readlines以及getcode等方法。
1.2 urlretrieve函数
这个函数可以方便的将网页上的一个文件保存到本地。以下代码可以非常方便的将百度的首页下载到本地:
from urllib import request
request.urlretrieve('http://www.baidu.com', "baidu.html")
1.3 urlencode函数
用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动的给我们进行编码。而如果使用代码发送请求,那么就必须手动的进行编码,这时候就应该使用urlencode函数来实现。urlencode可以把字典数据转换为URL编码的数据。示例代码如下:
from urllib import parse
data = {"name": "爬虫基础", "greet": "hello world","age":100}
qs = parse.urlencode(data)
print(qs)#name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100
1.4 parse_qs函数
可以将经过编码后的url参数进行解码。示例代码如下:
from urllib import parse
qs_str = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100"
data = parse.parse_qs(qs_str)
print(data) # {'name': ['爬虫基础'], 'greet': ['hello world'], 'age': ['100']}
1.5 urlparse和urlsplit
有时候拿到一个url,想要对这个url中的各个组成部分进行分割,那么这时候就可以使用urlparse或者是urlsplit来进行分割。示例代码如下:
from urllib import request, parse
url = "http://www.baidu.com/s;hello?usernme=zhiliao"
result1 = parse.urlsplit(url)
print(result1)
result2 = parse.urlparse(url)
print(result2)
print("result2-->params :", result2.params)
result = result1
print("scheme:", result.scheme)
print("netloc:", result.netloc)
print("path:", result.path)
print("query:",result.query)
"""
SplitResult(scheme='http', netloc='www.baidu.com', path='/s;hello', query='usernme=zhiliao', fragment='')
ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='hello', query='usernme=zhiliao', fragment='')
result2-->params : hello
scheme: http
netloc: www.baidu.com
path: /s;hello
query: usernme=zhiliao
"""
1.6 request.Request类
如果想要在请求的时候增加一些请求头,那么就必须使用request.Request类来实现。比如要增加一个User-Agent,示例代码如下:
from urllib import request
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"}
req = request.Request("http://www.baidu.com/", headers=headers)
resp = request.urlopen(req)
print(resp.read())
1.7 测试:用Request爬取拉勾网数据
from urllib import request,parse
url = "https://www.lagou.com/jobs/positionAjax.json?city=%E5%8C%97%E4%BA%AC&needAddtionalResult=false"
headers = {
"Referer": "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=",
"User-Agent": "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
'Origin': 'https://www.lagou.com',
"cookie": "xxxx"
}
data = {
"first": "true",
"pn": 1,
"kd": "python"
}
data_bytes = parse.urlencode(data).encode("utf-8") #
req = request.Request(url, headers=headers, data=data_bytes, method="POST")
resp = request.urlopen(req)
print(resp.read().decode("utf-8"))
'''
如果不添加cookie , 后台将返回:
{"status":false,"msg":"您操作太频繁,请稍后再访问","clientIp":"182.90.222.179","state":2402}
被识别出来
'''
1.8 ProxyHandler处理器(代理设置)
很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。urllib中通过ProxyHandler来设置使用代理服务器,下面代码说明如何使用自定义opener来使用代理:
1、代理的原理:在请求目的网站之前,先请求代理服务器,如何让代理服务去请求目的网站,
代理服务器拿到目的网站的数据后,在转发给我们的代码
2、http://httpbin.org:这个网站可以方便的查看http请求的一下参数
3、在代码中使用代理:
(1)使用 urllib.request.ProxyHandler, 传入一个代理,这个代理是一个字典,
字典的key依赖于代理服务器能都接收的类型, 一般是 http 或是 https, 值是 ip:port
(2)使用上一步创建的 handler, 以及 request.build_opener 创建一个 opener 对象
(3)使用上一步创建的 opener 调用 open 方法, 发起请求
from urllib import request
# 没有使用代理的情况
# url = "http://httpbin.org/ip"
# resp = request.urlopen(url)
# print(resp.read().decode("utf-8"))
# 使用代理的情况
url = "http://httpbin.org/ip"
# 1、使用ProxyHandler 传入代理构建一个handler
handler = request.ProxyHandler({"http": "111.111.222.222:8080"})
# 2、使用上面创建的handler构建一个opener
opener = request.build_opener(handler)
# 3、使用opener去发送一个请求
resp = opener.open(url)
print(resp.read().decode("utf-8"))
# 测试过程中可能由于代理服务器问题,没能请求成功
常用的代理有:
- 西刺免费代理IP:http://www.xicidaili.com/
- 快代理:http://www.kuaidaili.com/
- 代理云:http://www.dailiyun.com/
下面是使用在快代理上购买服务的测试代码(引用)
from urllib import request, parse
api_url = "http://xxxxxxxxxx"
resp = request.urlopen(api_url)
proxy_ip_port = resp.read().decode("utf-8")
print(proxy_ip_port)
proxy = {
"http": proxy_ip_port
}
# 使用代理的情况
url = "http://httpbin.org/ip"
# 1、使用ProxyHandler 传入代理构建一个handler
handler = request.ProxyHandler(proxy)
# 2、使用上面创建的handler构建一个opener
opener = request.build_opener(handler)
# 3、使用opener去发送一个请求
resp = opener.open(url)
print("通过代理返回的结果:{}".format(resp.read().decode("utf-8")))
二、cookie
2.1 什么是cookie
在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
2.2 cookie的格式
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
参数意义:
-
NAME
:cookie的名字。 -
VALUE
:cookie的值。 -
Expires
:cookie的过期时间。 -
Path
:cookie作用的路径。 -
Domain
:cookie作用的域名。 -
SECURE
:是否只在https协议下起作用。
2.3 使用cookielib库和HTTPCookieProcessor模拟登录
Cookie 是指网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。
这里以我搭建的一个管理端为例。要访问管理端的内容管理页面,必须先登录才能访问,登录说白了就是要有cookie信息。那么如果我们想要用代码的方式访问,就必须要有正确的cookie信息才能访问。解决方案有两种,第一种是使用浏览器访问,然后将cookie信息复制下来,放到headers中。示例代码如下:
from urllib import request
csdn_url = "http://xxxxxx/"
headers = {
"User-Agent": "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
"Referer": "http://xxxxxx",
"Cookie": "xxx"
}
req = request.Request(csdn_url, headers=headers)
resp = request.urlopen(req)
# print(resp.read().decode("utf-8"))
with open("cookie.html", "wb") as f:
f.write(resp.read())
'''
在没有设置 Cookie 的情况下,请求url 获取到的是登录页面的数据
设置了有效的 Cookie 数据之后,能正确获取到页面数据
'''
但是每次在访问需要cookie的页面都要从浏览器中复制cookie比较麻烦。在Python处理Cookie,一般是通过http.cookiejar
模块和urllib模块的HTTPCookieProcessor
处理器类一起使用。http.cookiejar
模块主要作用是提供用于存储cookie的对象。而HTTPCookieProcessor
处理器主要作用是处理这些cookie对象,并构建handler对象。
2.4 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实例。
利用http.cookiejar和request.HTTPCookieProcessor登录人人网。
from urllib import request, parse
from http.cookiejar import CookieJar
# 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 发送登陆的请求(账号和密码)
headers = {
"User-Agent": "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"
}
data = {
"email":"880151247@qq.com",
"password":"xxxxx"
}
login_url = "http://www.renren.com/PLogin.do"
data_bytes = parse.urlencode(data).encode("utf-8")
req = request.Request(url=login_url, headers=headers, data=data_bytes)
opener.open(req) # 这里为了获得 Cookie 不用接受返回,Cookie 会存在 cookiejar
#2、访问个人主页
admin_url = "http://renren.com/880151247/profile/"
# 获得个人主页的页面的时候,不用新建一个opener
# 而应该使用之前的那个 opener, 因为之前的那个 opener 已经包含了登陆需要的 cookie 信息
req = request.Request(admin_url, headers=headers)
resp =opener.open(req)
with open("admin.html", "wb") as f:
f.write(resp.read())
2.5 保存cookie到本地
保存cookie
到本地,可以使用cookiejar
的save
方法,并且需要指定一个文件名:
cookiejar.save(ignore_discard=True, ignore_expires=True)
ignore_discard = True : 即使cookies将被丢弃也将它保存下来
ignore_expires = True : 如果cookies已经过期也将它保存并且文件已存在时将覆盖
"""
本文通过 httpbin.org 提供的接口提交一个 cookie,设置成功后服务器会返回设置的 cookie 让浏览器保存
"""
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar = MozillaCookieJar("cookie.txt")
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)
headers = {
"User-Agent": "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"
}
req = request.Request("http://httpbin.org/cookies/set?myCookie=A0001", headers=headers)
resp =opener.open(req)
print(resp.read().decode("utf-8"))
# 设置 废弃 和 过期 的 cookie 都保存下来
cookiejar.save(ignore_discard=True, ignore_expires=True)
"""
结果 cookit.txt 文件中保存内容如下
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
httpbin.org FALSE / FALSE myCookie A0001
"""
2.6 从本地加载cookie
从本地加载cookie,需要使用cookiejar的load方法,并且也需要指定方法:
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar2 = MozillaCookieJar("cookie2.txt")
cookiejar2.load(ignore_discard=True, ignore_expires=True)
handler2 = request.HTTPCookieProcessor(cookiejar2)
opener2 = request.build_opener(handler2)
# 打印现有保存的 cookie
for c in cookiejar2:
print(c)
"""
cookie2.txt 文件
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
httpbin.org FALSE / FALSE myCookie1 A0001
httpbin.org FALSE / FALSE myCookie2 A0002
打印结果:
<Cookie myCookie1=A0001 for httpbin.org/>
<Cookie myCookie2=A0002 for httpbin.org/>
"""