目录
一、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模拟登录
http.cookiejar模块
登录自己搭建的网站
保存cookie到本地
从本地加载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_bak.html")
1.3 urlencode函数
用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动的给我们进行编码。而如果使用代码发送请求,那么就必须手动的进行编码,这时候就应该使用urlencode函数来实现。urlencode可以把字典数据转换为URL编码的数据。示例代码如下:
from urllib import parse
data = {"name": "爬虫基础", "age": 90}
qs = parse.urlencode(data)
print(qs) # name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&age=90
1.4 parse_qs函数
可以将经过编码后的url参数进行解码。示例代码如下:
from urllib import parse
qs_str = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&age=90"
data = parse.parse_qs(qs_str)
print(data) # {'name': ['爬虫基础'], 'age': ['90']}
1.5 urlparse和urlsplit
有时候拿到一个url,想要对这个url中的各个组成部分进行分割,那么这时候就可以使用urlparse或者是urlsplit来进行分割。示例代码如下:
from urllib import request, parse
url = "http://www.baidu.com/s;hello?usernme=zhiliao#101"
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='101')
ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='hello', query='usernme=zhiliao', fragment='101')
result2-->params : hello
scheme: http
netloc: www.baidu.com
path: /s;hello
query: usernme=zhiliao
"""
urlparse和urlsplit基本上是一模一样的。唯一不一样的地方是,urlparse里面多了一个params属性,而urlsplit没有这个params属性。比如有一个url为:url = 'http://www.baidu.com/s;hello?wd=python&username=abc#1',
那么urlparse可以获取到hello,而urlsplit不可以获取到。url中的params也用得比较少。
1.6 request.Request类:
如果想要在请求的时候增加一些请求头,那么就必须使用request.Request类来实现。比如要增加一个User-Agent,示例代码如下:
from urllib import request
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 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%B9%BF%E5%B7%9E&needAddtionalResult=false"
headers = {
"Referer": "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER",
'Origin': 'https://www.lagou.com',
"cookie": "LGUID=20161229121751-c39adc5c-cd7d-11e6-8409-5254005c3644; user_trace_token=20210531172956-5c418892-9a48-4fa1-8377-2c4f7a20b741; LG_HAS_LOGIN=1; hasDeliver=0; privacyPolicyPopup=false; WEBTJ-ID=20210531185241-179c20de542206-0e1348daf26807-2b6f686a-1049088-179c20de543150; sajssdk_2015_cross_new_user=1; RECOMMEND_TIP=true; __SAFETY_CLOSE_TIME__21787087=1; __lg_stoken__=677cc1b348553c3ed5e9cbb7b390a2ff300eb24fefe8a8e97e42e2872fc9543fba2800c9390bbd1d173c49e0c0362f67288bd32b2db49b0ed2db58d21a0b452d975350e4ed22; index_location_city=%E5%B9%BF%E5%B7%9E; login=false; unick=""; _putrc=""; JSESSIONID=ABAAAECABIEACCAAF01E6707FDF7DE8820405BA09C6C439; sensorsdata2015session=%7B%7D; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2221787087%22%2C%22first_id%22%3A%22179c20de60575-03879bc46582c2-2b6f686a-1049088-179c20de606146%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24os%22%3A%22Windows%22%2C%22%24browser%22%3A%22Chrome%22%2C%22%24browser_version%22%3A%2257.0.2987.98%22%7D%2C%22%24device_id%22%3A%22179c20de60575-03879bc46582c2-2b6f686a-1049088-179c20de606146%22%7D; _gid=GA1.2.1174524155.1622458625; X_HTTP_TOKEN=34e72e60c648e0f973806422611a51a83da2b43601; _ga=GA1.2.2125950788.1622453397; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1622453401,1622453584,1622458348,1622460836; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1622460836; LGRID=20210531193420-de9f4106-792c-4b58-ba57-e23c467d0128; TG-TRACK-CODE=index_search; SEARCH_ID=ea9769f0cf34489a97b947fba98efdb0"
}
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":"14.23.114.195","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": "210.61.240.162: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
# 为了测试这个功能,在 快代理 上找的免费代理老是访问不了,花了 6 元买了一天的代理测试成功
api_url = "http://kps.kdlapi.com/api/getkps/?orderid=90225131796xxxx&num=1&pt=1&sep=1"
print("api_url = {}".format(api_url))
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://47.106.134.xx:10086/wp-blog/wp-admin/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER",
"Referer": "http://47.106.134.xx:10086/wp-blog/wp-login.php",
"Cookie": "wordpress_143dbe2bf39634bb00ebe77d685bad79="
"admin%7C1623728016%7CTizOsc9GjD9BVvku7NSAUUYHdhdsNP3wKCrKj0AurSF%"
"7C3ebadcce94763d4e004793919da9fabb87431cecb47ea539a9871c067364ec91; "
"wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_143dbe2bf39634bb00ebe77d685bad79"
"=admin%7C1623728016%7CTizOsc9GjD9BVvku7NSAUUYHdhdsNP3wKCrKj0AurSF%7C099f9d1ffeb11c6f155feee"
"c7f7c25e0c0092aa4f789709d2b10c2b04fcccf84; "
"wp-settings-1=libraryContent%3Dbrowse; wp-settings-time-1=1622518418"
}
req = request.Request(csdn_url, headers=headers)
resp = request.urlopen(req)
# print(resp.read().decode("utf-8"))
with open("test_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对象。
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": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
}
data = {
"log":"1130647833@qq.com",
"pwd":"abc182355",
"wp-submit":"Log In",
"redirect_to":"http://47.106.134.xx:10086/wp-blog/wp-admin/",
"testcookie":"1"
}
login_url = "http://47.106.134.xx:10086/wp-blog/wp-login.php"
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://47.106.134.xx:10086/wp-blog/wp-admin/"
# 获得个人主页的页面的时候,不用新建一个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())
封装成函数版本
"""
通过python 登陆获取 cookie :封装成方法
"""
from urllib import request, parse
from http.cookiejar import CookieJar
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
}
def get_opener():
# 1、登录
# 1.1、创建一个 cookiejar 对象
cookiejar = CookieJar()
# 1.2、使用 cookiejar 创建一个 HTTPCookieProcess 对象
handler = request.HTTPCookieProcessor(cookiejar)
# 1.3、使用上一步创建的 handler 创建一个 opener
opener = request.build_opener(handler)
return opener
def login(opener):
# 1.4、使用 opener 发送登陆的请求(账号和密码)
data = {
"log":"123057120@qq.com",
"pwd":"abc102256",
"wp-submit":"Log In",
"redirect_to":"http://47.106.134.xx:10086/wp-blog/wp-admin/",
"testcookie":"1"
}
login_url = "http://47.106.134.xx:10086/wp-blog/wp-login.php"
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
def visit_profile(opener):
#2、访问个人主页
admin_url = "http://47.106.134.xx:10086/wp-blog/wp-admin/"
# 获得个人主页的页面的时候,不用新建一个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())
if __name__ == '__main__':
opener = get_opener()
login(opener)
visit_profile(opener)
保存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": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
}
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
"""
从本地加载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/>
"""