1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > python网络爬虫系列教程——python中urllib urllib2 cookie模块应用全解

python网络爬虫系列教程——python中urllib urllib2 cookie模块应用全解

时间:2024-04-28 22:24:12

相关推荐

python网络爬虫系列教程——python中urllib urllib2 cookie模块应用全解

全栈工程师开发手册 (作者:栾鹏)

python教程全解

python数据挖掘库urllib、urllib2、cookie知识全解。本文使用python2.7环境,如果需要使用python3的环境只需要按照下面的对应关系替换即可。

注意:python3.4以后中,将urllib2、urlparse、robotparser并入了urllib模块,并且修改了urllib模块,其中包含了5个子模块,每个子模块中的常用方法如下:

python3中的库 python2中的库urllib.error:ContentTooShortError;URLError;HTTPErrorurllib.parse: urlparse;_splitparams;urlsplit;urlunparse;urlunsplit;urljoin;urldefrag;unquote_to_bytes;unquote;parse_qs;parse_qsl;unquote_plus;quote;quote_plus;quote_from_bytes;urlencode;to_bytes;unwrap;splittype;splithost;splituser;splitpasswd;splitport等;urllib.request: urlopen; install_opener; urlretrieve; urlcleanup; request_host; build_opener; _parse_proxy;ProxyHandler;HTTPCookieProcessor; parse_keqv_list; parse_http_list; _safe_gethostbyname; ftperrors; noheaders; getproxies_environment; proxy_bypass_environment; _proxy_bypass_macosx_sysconf; Request等urllib.response: addbase; addclosehook; addinfo;addinfourl;urllib.robotparser: RobotFileParser

在Pytho2.x中使用import urllib2——-对应的,在Python3.x中会使用import urllib.request,urllib.error。

在Pytho2.x中使用import urllib——-对应的,在Python3.x中会使用import urllib.request,urllib.error,urllib.parse。

在Pytho2.x中使用import urlparse——-对应的,在Python3.x中会使用import urllib.parse。

在Pytho2.x中使用import urlopen——-对应的,在Python3.x中会使用import urllib.request.urlopen。

在Pytho2.x中使用import urlencode——-对应的,在Python3.x中会使用import urllib.parse.urlencode。

在Pytho2.x中使用import urllib.quote——-对应的,在Python3.x中会使用import urllib.request.quote。

在Pytho2.x中使用cookielib.CookieJar——-对应的,在Python3.x中会使用http.CookieJar。

在Pytho2.x中使用urllib2.Request——-对应的,在Python3.x中会使用urllib.request.Request。

python2.7环境,以下的所有程序需要导入以下库

#coding:utf-8import urllibimport urllib2import cookielib

python3.6环境下,以下的所有程序需要导入以下库

#coding:utf-8import urllibimport http.cookiejar as cookielib

本文使用python3.6环境调试

urllib.parse.urlparse模块,网址字符串处理

在python2中是urllib2.urlparse模块。

包含了将网址分解为6元组,将6元组分解为网址,获取指定网址上的链接所代表的绝对网址。

#urlparse()参数:网址、网络协议、是否使用片段,返回值:网络协议、服务器所在地、文件路径、可选参数、键值对、文档锚prot_sch,net_loc,path,params,query,frag=urllib.parse.urlparse("/index/index/index.html",None,None)print(prot_sch,net_loc,path,params,query,frag)#urlunparse()将6元组合并为网址字符串urlpath=urllib.parse.urlunparse((prot_sch,net_loc,path,params,query,frag))print(urlpath)#urljoin()获取根域名,连接新网址urlpath=urllib.parse.urljoin("/index/index/index.html","../chanpin/detail.html")print(urlpath)

urllib.request.urlretrieve模块:下载读取远程静态文件

在python2中是urllib.urlretrieve模块。

主要包含远程文件的下载,远程文件存储到本地,远程文件的读取,以及http响应的MIME头信息。

所谓的MIME头就是http协议中,数据传输都是以字节流在网线中传递,在一个文件或数据的传递起始部分都有个MIME头,用来描述本次传递的某些属性特点,如图中上面红色框中的内容。下面的红色框为传输的文件内容。

#远程文件resphonse = urllib.request.urlopen("/index/index/index.html")# urlopen(url,data,timeout)打开远程文件,返回的是类文件对象,可以使用readline等文件函数htmlcode = resphonse.readline() #读取一行htmlcode = resphonse.readlines() #读取所有行htmlcode = resphonse.read() #读取字节流print(resphonse.geturl()) #文件网址print(resphonse.info()) #数据传输的MIME头文件resphonse.close() #关闭urllib.request.urlretrieve("/index/index/index.html",'index.html')# 下载远程文件,参数为网址,可本地存储地址

urllib.request.Request模块:获取get方式请求响应流

在python2中是urllib2.Request模块。

所谓get方式,就是将请求数据序列化以后添加到网址中,打开指定网址的过程。

request = urllib.request.Request('/web/getdiaryurl?diaryid=612')try:resphonse = urllib.request.urlopen(request)# urlopen(url,data,timeout)打开远程文件,返回的是类文件对象,可以使用readline等文件函数except urllib.error.URLError as e: #本机没联网、连接不到服务器、服务器不存在print(e.reason)except urllib.error.HTTPError as e: #响应状态,响应码print(e.reason,e.code)print(resphonse.read()) #读取响应数据

urllib.request.Request模块:获取post方式请求响应流

在python2中是urllib2.Request模块。

post方式就是向指定的网址发送一段数据的仿真,所以请求过程除了请求网址,还有请求数据,两个参数来创建请求对象。

postobject={"diaryid":"612"} #将字典数据序列化postdata = urllib.parse.urlencode(postobject) # urlencode()字典序列化postdata = postdata.encode('utf-8')#将字符串编码成字节数组url= "/web/getdiaryurl"request = urllib.request.Request(url,postdata) #创建post请求对象,get请求对象:urllib2.Request(url+"?"+data)resphonse = urllib.request.urlopen(request) #post请求消息print(resphonse.read()) #读取响应数据

而对于我们想要爬取的网站,如何知道需要发送什么数据呢,需要用到浏览器的监听功能了。

这里以有道翻译为例,我们希望像服务器发送需要翻译的内容,获取翻译的结果,那么应该发送什么样的内容呢。

打开有道翻译的网址/

右键检查(审查元素)-切换到Network切换到网络监听部分。

在左侧翻译区输入你要翻译的内容如“jack”,回车后网页自动翻译,获取了翻译结果“杰克”,同时我们看到在右侧网络监听部分,已经显示出在此过程中所有的信息交互。

我们点击第一个信息交互记录,可以进入此次交互的详情。包括http头(MIME),和请求数据的格式。我们要发送的数据格式就按照图中的格式添加就可以了。

urllib.error异常

urllib.error有两个方法,URLError和HTTPError

URLError是OSError的一个子类,HTTPError是URLError的一个子类,服务器上HTTP的响应会返回一个状态码,根据这个HTTP状态码,我们可以知道我们的访问是否成功。200状态码,表示请求成功,再比如常见的404错误等。

最后值得注意的一点是,如果想用HTTPError和URLError一起捕获异常,那么需要将HTTPError放在URLError的前面,因为HTTPError是URLError的一个子类。如果URLError放在前面,出现HTTP异常会先响应URLError,这样HTTPError就捕获不到错误信息了。

urllib.request.Request模块:控制http头

在python2中是urllib2.Request模块。

很多服务器或代理服务器会查看HTTP头,进而控制网络流量,实现负载均衡,限制不正常用户的访问。所以我们要学会设置HTTP头,来保证一些访问的实现。

网站的HTTP头的设置,可以通过网页右键审查元素中查看,同上图。

HTTP头部分参数说明:

Upgrade-Insecure-Requests:参数为1。该指令用于让浏览器自动升级请求从http到https,用于大量包含http资源的http网页直接升级到https而不会报错。简洁的来讲,就相当于在http和https之间起的一个过渡作用。就是浏览器告诉服务器,自己支持这种操作,我能读懂你服务器发过来的上面这条信息,并且在以后发请求的时候不用http而用https;

User-Agent:有一些网站不喜欢被爬虫程序访问,所以会检测连接对象,如果是爬虫程序,也就是非人点击访问,它就会不让你继续访问,所以为了要让程序可以正常运行,我们需要设置一个浏览器的User-Agent;

Accept:浏览器可接受的MIME类型,可以根据实际情况进行设置;

Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间;

Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到;

Cookie:这是最重要的请求头信息之一。中文名称为“小型文本文件”或“小甜饼“,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。定义于RFC2109。是网景公司的前雇员卢·蒙特利在1993年3月的发明。

url= "/p/30488000"postdata = urllib.parse.urlencode({"p":"30488000"}) # urlencode()字典序列化headers={}headers["User-Agent"]='Mozilla/4.0 (compatible;MSIE 5.5;Windows NT)' #标明浏览器身份,有些服务器或代理服务器会来判断。这里模仿的是IE浏览器headers["Referer"]='/p' #标明文件来源,防止盗链用的headers["Content-Type"]='text/html' #在谁用rest接口的服务器会检测这个值,来确定内容如何解析request = urllib.request.Request(url,headers=headers) #headers控制请求,因为服务器会根据这个控制头决定如何响应。(resphonse.info()可以查看响应的头的信息)resphonse = urllib.request.urlopen(request) #post请求消息print(resphonse.read()) #读取响应数据

常见的User Agent

1.Android

Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19

Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Mozilla/5.0 (Linux; U; Android 2.2; en-gb; GT-P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

2.Firefox

Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/0101 Firefox/21.0

Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0

3.Google Chrome

Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36

Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19

4.iOS

Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3

Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A101a Safari/419.3

上面列举了Andriod、Firefox、Google Chrome、iOS的一些User Agent,直接copy就能用。

urllib.request.ProxyHandler函数:设置代理服务器,防止限制IP

在python2中是urllib2.ProxyHandler函数。

控制代理服务器,防止服务器限制IP。每隔一段时间换一个代理服务器

代理服务器的ip你可以从网页中自己选择和定期更换

URL:/

#控制代理服务器,防止服务器限制IP。每隔一段时间换一个代理服务器enable_proxy = Trueproxy_handler=urllib.request.ProxyHandler({"http":"61.135.217.7:80"})null_proxy_handler = urllib.request.ProxyHandler({})if enable_proxy:opener = urllib.request.build_opener(proxy_handler)else:opener = urllib.request.build_opener(null_proxy_handler)urllib.request.install_opener(opener)

使用install_opener方法之后,会将程序默认的urlopen方法替换掉。也就是说,如果使用install_opener之后,在该文件中,再次调用urlopen会使用自己创建好的opener。如果不想替换掉,只是想临时使用一下,可以使用opener.open(url),这样就不会对程序默认的urlopen有影响。

编写代码访问.tw/,该网站是测试自己IP为多少的网址,服务器会返回访问者的IP。在使用代理服务器以后,访问这里查询本地IP地址的网址的返回结果也会由于代理服务器的存在而随机变化。

下面实现了一个爬虫,爬取/ 网站中代理服务器的列表。

#coding:utf-8#本实例用于获取国内高匿免费代理服务器import urllibfrom bs4 import BeautifulSoupdef getdata(html): #从字符串中安装正则表达式获取值allproxy = [] # 所有的代理服务器信息soup = BeautifulSoup(html, 'html.parser')alltr = soup.find_all("tr", class_="")[1:] #获取tr ,第一个是标题栏,去除for tr in alltr:alltd =tr.find_all('td')oneproxy ={'IP地址':alltd[1].get_text(),'端口号': alltd[2].get_text(),# '服务器地址': alltd[3].a.get_text(),'是否匿名': alltd[4].get_text(),'类型': alltd[5].get_text(),'速度': alltd[6].div['title'],'连接时间': alltd[7].div['title'],'存活时间': alltd[8].get_text(),'验证时间': alltd[9].get_text(),}allproxy.append(oneproxy)alltr = soup.find_all("tr", class_="odd")[1:] # 获取tr ,第一个是标题栏,去除for tr in alltr:alltd = tr.find_all('td')oneproxy = {'IP地址': alltd[1].get_text(),'端口号': alltd[2].get_text(),# '服务器地址': alltd[3].a.get_text(),'是否匿名': alltd[4].get_text(),'类型': alltd[5].get_text(),'速度': alltd[6].div['title'],'连接时间': alltd[7].div['title'],'存活时间': alltd[8].get_text(),'验证时间': alltd[9].get_text(),}allproxy.append(oneproxy)return allproxy#根据一个网址,获取该网址中符合指定正则表达式的内容def getallproxy(url='"/nn"'):try:# 构造 Request headersagent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER'headers = { # 这个http头,根据审查元素,监听发包,可以查看"Host": "","Referer": "/",'User-Agent': agent}request = urllib.request.Request(url, headers=headers) # 创建一个请求response = urllib.request.urlopen(request) # 获取响应html = response.read() #读取返回html源码return getdata(html)except urllib.error.URLError as e:if hasattr(e,"code"):print(e.code)if hasattr(e,"reason"):print(e.reason)return []# allproxy = getallproxy()# print(allproxy)

有了上面的列表就可以直接从数组中随机选择一个代理服务器。

allproxy = proxy.getallproxy() #获取一批代理服务器列表...oneproxy = random.choice(allproxy) #随机选择一个代理服务器proxy_handler = urllib.request.ProxyHandler({"http": oneproxy['IP地址']+":"+oneproxy['端口号']}) #将代理服务器ip绑定到请求对象中

urllib.request.HTTPCookieProcessor函数:设置cookie

在python2中是urllib2.HTTPCookieProcessor函数

cookie=cookielib.CookieJar() #声明一个CookieJar对象实例来保存cookiehandler=urllib.request.HTTPCookieProcessor(cookie) #利用urllib2库的HTTPCookieProcessor对象来创建cookie处理器opener=urllib.request.build_opener(handler) #通过handler来构建openerresphonse=opener.open('/luanpeng825485697/article/details/78264170') #cookie是由服务器来设定的存储在客户端,客户端每次讲cookie发送给服务器来携带数据for item in cookie:print('Name='+item.name)print('Value='+item.value)

cookie模块:将cookie写入文件

filename='cookie.txt'cookie=cookielib.MozillaCookieJar(filename) #声明一个MozillaCookieJar对象实例来保存cookie,之后写入文件handler=urllib.request.HTTPCookieProcessor(cookie) #利用urllib2库的HTTPCookieProcessor对象来创建cookie处理器opener = urllib.request.build_opener(handler) #通过handler来构建openerresphonse=opener.open('/luanpeng825485697/article/details/78264170') #创建一个请求,原理同urllib2的urlopencookie.save(ignore_discard=True, ignore_expires=True) #保存cookie文件

ookie.save的参数说明:

ignore_discard的意思是即使cookies将被丢弃也将它保存下来;

ignore_expires的意思是如果在该文件中cookies已经存在,则覆盖原文件写入。

在这里,我们将这两个全部设置为True。

运行之后,cookies将被保存到cookie.txt文件中。我们可以查看自己查看下cookie.txt这个文件的内容。

cookie模块:从文件中读取cookie

cookie=cookielib.MozillaCookieJar() #声明一个MozillaCookieJar对象实例cookie.load("cookie.txt",ignore_discard=True, ignore_expires=True) #从文件中读取cookie内容到变量req=urllib.request.Request("/luanpeng825485697/article/details/78264170") #创建请求的requestopener=urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie)) #利用urllib2的build_opener方法创建一个openerresponse=opener.open(req) #使用包含了指定cookie的opener发起请求print(resphonse.read()) #打印响应

cookie模块:利用cookie模拟登陆

创建一个带有cookie的opener,在访问登录的URL时,将登录后的cookie保存下来,然后利用这个cookie来访问其他网址

现在很多网站需要登陆后才能访问,如知乎,地址

在没有登陆时访问这个网址,只能出现登陆界面

如果登陆以后,在访问这个网址,就会出现文章列表。

这是因为访问此地址,知乎服务器会查询请求cookie,如果请求cookie没有用户信息,就证明没有登陆,就会返回登陆界面,如果有cookie信息就会返回文章列表界面,同时包含用户的其他信息。所以首先需要让自己的请求中能带有包含自己信息的cookie。这一步通过登陆来实现。

在登陆界面,通过post将用户账号密码发送给服务器,服务器会将用户信息以cookie的形式返回给用户,用户在下次请求时,就会自动将这个cookie添加到请求http头中,这样下次再访问时,服务器就知道这个用户已经登陆了。

所以在使用cookie模拟登陆,需要两步,第一步是获取cookie,第二步是将cookie添加到http中,模拟用户已经存在的方式请求文章。

第一步,登陆获取cookie(通过post向指定网址发送数据,获取返回cookie即可)

对于发送数据需要添加的post数据和http头可以通过审查元素监听。

由于浏览器的监听在跳转到新的网页就会清空重新监听,所以在登陆到文章列表页面,浏览先监听了登陆页面的数据,后清空监听记录,重新监听文章列表页面的数据。不能及时记录下载登陆界面发送的请求数据,所以建议使用fiddle监听数据。

不过也不是没有办法,监听区红色的记录开关按钮,可以及时的阻止监听。

这里在点击登陆后,我立刻点击了浏览监听中的红色记录按钮,拦截了登陆界面的数据。

可以看到需要发送的数据除了phone_num手机号、password密码、captcha_type验证码类型(选择不同的登陆方式需要发送的数据类型可以不同),还有一个_xsrf,这个字段是在登陆网页源代码中

所以在发送post前还要获取网页源代码解析这个字段。

# -*- coding: UTF-8 -*-import requests#import http.cookiejar as cookielibfrom bs4 import BeautifulSoupimport cookielib#post登陆信息,生成cookie文件session = requests.Session()session.cookies = cookielib.LWPCookieJar("cookie")agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/5.1.2.3000 Chrome/55.0.2883.75 Safari/537.36'headers = { #这个http头,根据审查元素,监听发包,可以查看"Host": "","Origin":"/","Referer":"/",'User-Agent':agent}postdata = {'phone_num': '18158208197', #填写手机号'password': '19910101a', #填写密码'captcha_type':'cn',}response = session.get("", headers=headers)soup = BeautifulSoup(response.content, "html.parser")xsrf = soup.find('input', attrs={"name": "_xsrf"}).get("value") #解析_xsrf字段postdata['_xsrf'] =xsrf #因为知乎登陆需要这个字段的消息result = session.post('/login/email', data=postdata, headers=headers) #发送数据session.cookies.save(ignore_discard=True, ignore_expires=True) #及时登陆失败也会生成cookie,不过这个cookie不能支持后面的模拟登陆状态

第二步、通过获取的cookie,模拟已经登陆的状态。这样再次访问知乎网址,就能获取文章了。

访问文章需要的http头可以通过审查元素查看。

# -*- coding: UTF-8 -*-import requests#import http.cookiejarfrom bs4 import BeautifulSoupimport cookielib#加载cookie文件模拟登陆session = requests.session()session.cookies = cookielib.LWPCookieJar(filename='cookie')try:session.cookies.load(ignore_discard=True)except:print("Cookie 未能加载")def isLogin():url = "/"login_code = session.get(url, headers=headers, allow_redirects=False).status_codeif login_code == 200:return Trueelse:return Falseif __name__ == '__main__':agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/5.1.2.3000 Chrome/55.0.2883.75 Safari/537.36'headers = {"Host": "","Origin": "/","Referer": "/",'User-Agent': agent,}if isLogin():print('您已经登录')

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。