03—小白学Python爬虫之urllib的基本和进阶使用及Get、Post示例

编程入门 行业动态 更新时间:2024-10-20 20:45:16

03—小白学Python爬虫之urllib的基本和<a href=https://www.elefans.com/category/jswz/34/1769503.html style=进阶使用及Get、Post示例"/>

03—小白学Python爬虫之urllib的基本和进阶使用及Get、Post示例

urllib库官方文档地址:.html

urllib简介

概述

urllib是python内置的HTTP请求库。

版本
  • python2.X —> urllib和urllib2
  • python3.X —> urllib
变化
  • 在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

urllib基本使用

接下来示例代码都是以python3.X中使用的urllib

模块
  • urllib.request 请求模块
  • urllib.error 异常处理模块
  • urllib.parse url解析模块
  • urllib.robotparser robots.txt解析模块
urlopen

方法参数:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

先来个入门示例:

from urllib import requestdef demo():"""直接使用urlopen打开网页,返回结果可以作为一个文件对象进行操作:return:"""with request.urlopen('') as f:# 读取返回的数据data = f.read()# 请求code码 200 404 500 403print('code:', f.getcode())# 返回实际数据的URLprint('url:', f.geturl())# 服务器返回的http报头信息print('info:', f.info())print('Status:', f.status, f.reason)for k, v in f.getheaders():print('%s: %s' % (k, v))print('Data:', data.decode('utf-8'))if __name__ == '__main__':demo()

如上,短短几行代码,就可以把baidu首页面的信息抓取下来。

构建urlrequest.Request对象

除了上面直接使用urlopen传入url打开网页,还可以通过构造Request对象来完成

def demo2():"""构建一个request对象,URL作为构造参数传入:return:"""req = request.Request('')resp = request.urlopen(req)print('resp:', resp.read().decode('utf-8'))

上篇文章说过request header相关信息,在header中,使用最多的就是User-Agent,有些网页为了防止别人恶意采集信息而做了一些反爬虫的设置,而我们在爬取时可以通过设置UA来模拟成浏览器来访问。

def demo3():headers = {'User-Agent': 'Mozilla/5.0'}req = request.Request('', headers=headers)resp = request.urlopen(req)print(resp.read().decode('utf-8'))
data参数-区别post和get

urlopen中,data参数如果为空,代表get请求,如果不为空,则代表post请求。

其中post数据,需要进行urlencode,如data=bytes(parse.urlencode(data)

示例:

def demo3():"""urlopen方法中增加data参数代表是一个post请求设置headers,比如UA:return:"""req = request.Request('')req.add_header('User-Agent', 'Mozilla/5.0')data = {'name': 'wangcai'}resp = request.urlopen(req, data=bytes(parse.urlencode(data), encoding='utf-8'))print(resp.read().decode('utf-8'))
timeout

有时候,网络不好或者服务器响应比较慢 请求异常等,需要给请求设置一个超时时间,及时做出反应,而不是让程序无限制等待。

def demo4():resp = request.urlopen("", timeout=0.01)print(resp.read().decode('utf-8'))

执行如上代码,会抛出如下异常:

  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1321, in do_openr = h.getresponse()File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1331, in getresponseresponse.begin()File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 297, in beginversion, status, reason = self._read_status()File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 258, in _read_statusline = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 586, in readintoreturn self._sock.recv_into(b)
socket.timeout: timed out

so,需要对异常进行处理,修改代码如下:

def demo4():try:resp = request.urlopen("", timeout=0.001)print(resp.read().decode('utf-8'))except error.URLError as e:if isinstance(e.reason, socket.timeout):print('timeout , stop')

输入结果为:

timeout , stop

如上,超时异常就拦截了,可以做自己的相关处理。

自定义opener
  • opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。

  • 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:

    • 使用相关的 Handler处理器 来创建特定功能的处理器对象;
    • 然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象;
    • 使用自定义的opener对象,调用open()方法发送请求。
  • 如果程序里所有的请求都使用自定义的opener,可以使用urllib.request.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)

示例:

from urllib import requestdef demo():# 构建一个HTTPHandler处理器对象,支持HTTP请求http_handler = request.HTTPHandler()# 调用urllib.request的build_opener方法,创建支持http请求的opener对象opener = request.build_opener(http_handler)# 构建request请求req = request.Request("")# 使用自定义opener对象的open方法,发送request请求response = opener.open(req)# 获取server响应print(response.read().decode('utf-8'))if __name__ == '__main__':demo()

如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。

# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求,同时开启Debug Log,debuglevel 值默认 0
http_handler = urllib2.HTTPHandler(debuglevel=1)# 构建一个HTTPSHandler 处理器对象,支持处理HTTPS请求,同时开启Debug Log,debuglevel 值默认 0
https_handler = urllib2.HTTPSHandler(debuglevel=1)
Handler处理器

很多网站会检测某一段时间某个IP的访问次数(通过流量统计 系统日志等方法),如果监测不正常的话,那就会封掉这个IP的访问。这个时候,我们可以通过设置代理服务器,定时更换IP进行爬取解决。

示例一:

def handler_demo():# 构建两个Handler,一个有代理IP,一个无httpproxy_handler = request.ProxyHandler({"http": "192.168.1.1:80"})nullproxy_handler = request.ProxyHandler()# 通过build_opener方法使用Handler代理对象,创建自定义openeropener = request.build_opener(httpproxy_handler)# 构建request请求req = request.Request("")# 使用代理,只有opener.open才会生效,urlopen无效response = opener.open(req)print(response.read().decode('utf-8'))# 如果使用request.install_opener(opener),那么不管使用opener.open()还是urlopen()都将使用代理

示例二:

def handler_demo2():"""代理足够多,可以随机选择一个去访问:return: """proxy_list = [{"http": "101.200.24.123:80"},{"http": "101.200.24.123:80"},{"http": "101.200.24.123:80"},{"http": "101.200.24.123:80"},]proxy = random.choice(proxy_list)handler = request.ProxyHandler(proxy)opener = request.build_opener(handler)req = request.Request("")response = opener.open(req)print(response.read().decode('utf-8'))
HTTPPasswordMgrWithDefaultRealm

HTTPPasswordMgrWithDefaultRealm
创建一个密码管理对象,用来保存HTTP请求相关的用户名和密码。

主要两个场景:
1. 验证代理授权的用户名和密码(proxyBasicAuthHandler)
2. 验证web客户端的用户名和密码(HttpBasicAuthHandler)

ProxyBasicAuthHandler(代理授权验证)

如果我们使用之前的代码来使用私密代理,会报 HTTP 407 错误,表示代理没有通过身份验证:

HTTPError: HTTP Error 407: Proxy Authentication Required

所以我们需要改写代码,通过:

  • HTTPPasswordMgrWithDefaultRealm():来保存私密代理的用户密码
  • ProxyBasicAuthHandler():来处理代理的身份验证。

示例:

def pwd_demo():# 私密代理授权的账户 密码user = 'demo'pwd = '1234'# 私密代理IPproxy_server = '119.129.99.29:1231'# 构建一个密码管理对象,保存用户名和密码pwdmgr = request.HTTPPasswordMgrWithDefaultRealm()# 添加账户信息pwdmgr.add_password(None, proxy_server, user=user, passwd=pwd)# 构建一个代理基础用户名/密码验证的ProxyBasicAuthHandler对象,参数是创建的密码管理对象proxy_handler = request.ProxyBasicAuthHandler(pwdmgr)# 通过build_opener方法使用Handler创建自定义openeropener = request.build_opener(proxy_handler)# 构造request请求req = request.Request("")# 发送请求并打印响应response = opener.open(req)print(response.read().decode('utf-8'))
HTTPBasicAuthHandler处理器(Web客户端授权验证)

有些Web服务器(包括HTTP/FTP等)访问时,需要进行用户身份验证,爬虫直接访问会报HTTP 401 错误,表示访问身份未经授权:

HTTPError: HTTP Error 401: Unauthorized

如果我们有客户端的用户名和密码,我们可以通过下面的方法去访问爬取:

def pwd_demo2():# 私密代理授权的账户 密码user = 'wangcai'pwd = '12345qwertyui'# web客户端IPweb_server = '10.0.2.101:80'# 构建一个密码管理对象,保存用户名和密码pwdmgr = request.HTTPPasswordMgrWithDefaultRealm()# 添加账户信息pwdmgr.add_password(None, web_server, user=user, passwd=pwd)# 构建一个代理基础用户名/密码验证的HttpBasicAuthHandler对象,参数是创建的密码管理对象proxy_handler = request.HTTPBasicAuthHandler(pwdmgr)# 通过build_opener方法使用Handler创建自定义openeropener = request.build_opener(proxy_handler)# 构造request请求req = request.Request("")# 发送请求并打印响应(requesr.install_opener()执行后,全局生效)response = opener.open(req)print(response.read().decode('utf-8'))
异常处理
概念

在访问网页的过程中,可能会出现一些异常,比如404 500 超时等,程序需要对这些信息做异常处理

分类
  • URLError 只有一个属性reason,即异常发生的时候只能打印错误信息
  • HTTPError 是URLError的子类,有三个属性,code reason headers三个信息
示例
  • 示例一(URLError)
def demo():try:resp = request.urlopen("")print(resp.read().decode('utf-8'))except error.URLError as e:print(e.reason)

输出为:

[Errno 8] nodename nor servname provided, or not known
  • 示例二(HTTPError)
def demo2():try:resp = request.urlopen(".html")print(resp.read().decode('utf-8'))except error.HTTPError as e:print(e.reason, e.code, e.headers)except error.URLError as e:print(e.reason)else:print('success')

输出结果为:

Not Found 404 Server: openresty
Date: Tue, 06 Mar 2018 12:06:58 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 4144
Connection: close
Vary: Accept-Encoding
Set-Cookie: uuid_tt_dd=10_18754355060-1520338018722-773220; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn;
Set-Cookie: dc_session_id=10_1520338018722.227796; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn;
ETag: "5a324c78-1030"
通过reason做异常分析

可以通过捕获到的异常reason进行分析,比如超时,示例如下 :

def demo3():try:request.urlopen("", timeout=0.001)except error.URLError as e:print(type(e.reason))if isinstance(e.reason, socket.timeout):print('连接超时')

输出结果为:

<class 'socket.timeout'>
连接超时
概念
  • 指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据
  • 可以保持用户登录信息,与服务端进行通信
Cookie原理

HTTP是无状态的面向连接的协议, 为了保持连接状态, 引入了Cookie机制 Cookie是http消息头中的一种属性,包括:

Cookie名字(Name)
Cookie的值(Value)
Cookie的过期时间(Expires/Max-Age)
Cookie作用路径(Path)
Cookie所在域名(Domain),
使用Cookie进行安全连接(Secure)。前两个参数是Cookie应用的必要条件,另外,还包括Cookie大小(Size,不同浏览器对Cookie个数及大小限制是有差异的)。

Cookie由变量名和值组成,根据 Netscape公司的规定,Cookie格式如下:

Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
Cookie应用

Cookies在爬虫方面最典型的应用是判定用户是否已经登录,如果登录,在后续访问网站其他页面,需要携带server返回的cookie数据,这样就不需要重复登录了。

示例:

from urllib import request
import http.cookiejar
import ssldef demo():# 通过Chrome开发者工具获取到的headers信息headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8','Accept-Language': ':zh-CN,zh;q=0.9','Connection': 'keep-alive',# 如果没有这个数据,会获取不到内容'Cookie': 'SINAGLOBAL=14451465401860.67.1489663918038; UOR=,,www.cidu; ULV=15126380274353:39:2:1:654449358996.8848.15312638074260:1512122654080; YF-Page-G0=3d55e256bde550ac7b0d32a2ad7d6fa53; __ln4krntdmcvrd=-1; login_sid_t=764ees242ec6c2c671008097fe81d9776; cross_origin_praoto=SSL; YF-Ugrow-G0=ad8a3bc19dc1269e709f753b172bddb094; YF-V5-G0=020421dd53s5a1c903e89d913fb8a2988; WBStorage=c5ff51a335af29d81|undefined; WBtopGlobal_register_version=d7a77880fa9c5f84; SCF=ApB-0Hdxe1pH2EVUwj6T7lnFDhHVmpTrGutTGUCBqAxNpYokCZKUXDXjFb7jnhhuX52vPbRLRqP7Q1qC5LF6HDE.; SUB=_2A253mhxmDeRhGeVG71AR-SjEzz-IHXVU7gqurDV8asdasPUNbmtANLUOjkW9NT7lHG3qdhhmQlBxLcF_jvJiQRxBGY_6P; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh1676ff2MDLHTsnQwjrekN9-b5JpX5KzhUgL.FoeRShadaz71KqRShe2dJLoIEXLxK-LBo5L12235qLxKqLBoBL12zLxKBLB.2LB.2LxKqL1-eL1hWQqPW7wKz7eKnt; SUHB=0FQbL0-bhmNpOg; ALF=1551867826; SSOLoginState=1520331826; wvr=6; wb_timefeed_3842096843=1','Host': 'weibo','Referer': '=1','Upgrade-Insecure-Requests': '1','User-Agent': 'ozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',}url = '=1&pids=plc_main&ajaxpagelet=1&ajaxpagelet_v6=1&__ref=%2Fu%2F3842096843%2Fhome%3Fleftnav%3D1&_t=FM_152033182791241'# 构建request对象req = request.Request(url, headers=headers)# 不验证httpscontext = ssl._create_unverified_context()# 发送请求response = request.urlopen(req, context=context)# 打印响应内容print(response.read().decode('utf-8'))if __name__ == '__main__':demo()

如上,通过查看控制台,就能发现确实返回我的收藏内容,此处略。

但是这样过于复杂,需要先登录页面,通过工具抓包才能拿到cookie信息,那么有木有简单一点的呢?当然是有喽~

cookielib库和HTTPCookiePorcessor处理器

在Python处理Cookie,一般是通过cookielib模块和 urllib模块的HTTPCookieProcessor处理器类一起使用。

cookielib模块:主要作用是提供用于存储cookie的对象HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象。
cookielib库简介

该模块主要的对象有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实例。

大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar()

示例一(获取Cookie保存到CookieJar对象中)
from urllib import request
import http.cookiejar
import ssldef demo2():"""获取cookie,并保存在cookieJar对象中:return:"""# 构建cookieJar对象来保存cookiecookie_jar = http.cookiejar.CookieJar()# 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJarhttp_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar)# 构建openeropener = request.build_opener(http_cookie_processor)# 构建requestreq = request.Request("")# 发送请求response = opener.open(req)# 打印cookie信息for item in cookie_jar:print(item.name + '=' + item.value)print('done')

输出结果为:

BAIDUID=88BA4BF20ED5C2838A1C96CE468B767B:FG=1
BIDUPSID=88BA4BF20ED5C2838A1C96CE468B767B
H_PS_PSSID=1435_21106_17001_20718
PSTM=1520334302
BDSVRTM=0
BD_HOME=0
done
示例二(获取Cookie,并保存到本地文件中)
def demo3():"""获取cookie,并保存到cookie文件中:return:"""# 文件名cookie_filename = 'cookie_file.txt'# 构建cookieJar对象来保存cookiecookie_jar = http.cookiejar.MozillaCookieJar(filename=cookie_filename)# 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJarhttp_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar)# 构建openeropener = request.build_opener(http_cookie_processor)# 构建requestreq = request.Request("")# 发送请求response = opener.open(req)# 保存cookie信息cookie_jar.save()print('done')

执行完成后,会发现在当前目录下创建cookie_file.txt,内容为:

# Netscape HTTP Cookie File
# .html
# This is a generated file!  Do not edit..baidu  TRUE    /   FALSE   3667818295  BAIDUID E06113B9C530BDC0B53043B8D3E8E964:FG=1
.baidu  TRUE    /   FALSE   3667818295  BIDUPSID    E06113B9C530BDC0B53043B8D3E8E964
.baidu  TRUE    /   FALSE   3667818295  PSTM    1520334648
示例三(从文件中获取Cookie,并作为请求的一部分去访问)
def demo4():"""从文件中获取Cookie,并作为请求的一部分:return:"""# 创建MozillaCookieJar对象cookie_jar = http.cookiejar.MozillaCookieJar()# 文件名cookie_filename = 'cookie_file.txt'# 读取cookie内容cookie_jar.load(cookie_filename)# 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJarhttp_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar)# 构建openeropener = request.build_opener(http_cookie_processor)# 构建requestreq = request.Request("")# 发送请求response = opener.open(req)print('done')
使用Cookielib和post登录人人网
示例

登录人人网,然后再获取某人的页面数据信息

import http.cookiejar
from urllib import request, parsedef demo():# 1. 构建一个CookieJar对象实例来保存cookiecookie = http.cookiejar.CookieJar()# 2. 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象cookie_handler = request.HTTPCookieProcessor(cookie)# 3. 通过 build_opener() 来构建openeropener = request.build_opener(cookie_handler)# 4. addheaders 接受一个列表,里面每个元素都是一个headers信息的元祖, opener将附带headers信息opener.addheaders = [("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")]# 5. 需要登录的账户和密码data = {"email": "xxx@163", "password": "123456opmhsa"}# 6. 通过urlencode()转码postdata = bytes(parse.urlencode(data), encoding='utf-8')# 7. 构建Request请求对象,包含需要发送的用户名和密码req = request.Request(".do", data=postdata)# 8. 通过opener发送这个请求,并获取登录后的Cookie值,opener.open(req)# 9. opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面response = opener.open("")# 10. 打印响应内容print(response.read().decode('utf-8'))

如上,当用户名密码输入错误时,会返回如下信息:

<a class="close" href="javascript:closeError();"></a>
<p class="wrong">您的用户名和密码不匹配</p>
<p class="worp">为了账号安全,已向您的邮箱: <strong id="sendemail"></strong>发送了一封确认信,请通过邮件内链接登录。</p>
<p class="m-26"><a id="gotoEmail" href="#" target="_blank">打开邮箱查收确认信</a></p>
<p class="m-26"><a href="javascript:closeError();">重新输入</a></p>

当不登录直接访问目标页面时,会跳转到登录页面,提示需要登录才可以访问。

当输入正确用户名密码,通过cookieJar保存Cookie信息,再去获取主页面信息时,会发现可以拿到数据了,如下:

<head><meta name="Description" content="人人网 校内是一个真实的社交网络,联络你和你周围的朋友。 加入人人网校内你可以:联络朋友,了解他们的最新动态;和朋友分享相片、音乐和电影;找到老同学,结识新朋友;用照片和日志记录生活,展示自我。"/><meta name="Keywords" content="Xiaonei,Renren,校内,大学,同学,同事,白领,个人主页,博客,相册,群组,社区,交友,聊天,音乐,视频,校园,人人,人人网"/><title>人人网 - 邓**❤</title><meta charset="utf-8"/>

so,基于CookieJar和post模拟登录就搞定了。

注意事项
  • 登录一般都会先有一个HTTP GET,用于拉取一些信息及获得Cookie,然后再HTTP POST登录。
  • HTTP POST登录的链接有可能是动态的,从GET返回的信息中获取。
  • password 有些是明文发送,有些是加密后发送。有些网站甚至采用动态加密的,同时包括了很多其他数据的加密信息,只能通过查看JS源码获得加密算法,再去破解加密,非常困难。
  • 大多数网站的登录整体流程是类似的,可能有些细节不一样,所以不能保证其他网站登录成功。
  • 当然,我们也可以直接发送账号密码到登录界面模拟登录,但是当网页采用JavaScript动态技术以后,想封锁基于 HttpClient 的模拟登录就太容易了,甚至可以根据你的鼠标活动的特征准确地判断出是不是真人在操作。
  • 想做通用的模拟登录还得选别的技术,比如用内置浏览器引擎的爬虫(关键词:Selenium ,PhantomJS),这个我们将在后续说到。

get示例

贴吧爬取程序功能:
输入要抓取的贴吧名以及起始页和结束页,然后对页面进行爬取,并下载到本地。

from urllib import request, parse
import ssl"""
通过浏览器抓取URL发现,其真实URL为:=python&ie=utf-8&pn=50
kw为关键词
ie为编码格式
pn为查询列表起始位置,计算公式为:(current_page -1) * 50
"""def spiderHtml(page, fullurl):print('*' * 15 + '正在爬取第' + str(page) + '页数据')headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36'}context = ssl._create_unverified_context()req = request.Request(fullurl, headers=headers)response = request.urlopen(req, context=context)print('*' * 15 + '第' + str(page) + '页数据爬取完成')return response.read()def savehtml(page, html):"""保存抓取的页面数据:param page: 当前页:param html: 页面数据:return:"""with open('num' + str(page) + '.html', mode='wb+') as f:print('正在保存第%d页信息' % page)f.write(html)print('第%d页信息保存成功' % page)def mainEntrance(url, startpage, endpage):"""爬虫主入口:param url: 基础URL:param startpage: 起始页:param endpage: 结束页:return:"""for page in range(startpage, endpage + 1):pn = (page - 1) * 50fullurl = url + '&' + str(pn)html = spiderHtml(page, fullurl)savehtml(page, html)if __name__ == '__main__':keyword = input("请输入贴吧名:")startpage = int(input("请输入起始页:"))endpage = int(input("请输入结束页:"))data = {'kw': keyword}encodeData = parse.urlencode(data)url = '?' + encodeDatamainEntrance(url, startpage, endpage)

post示例

以有道字典,翻译”hello”为例。
通过Chrome浏览器开发者工具,监控发现,其Request Header, Response Header以及form data如下:

"""
General:Request URL:=dict&smartresult=ruleRequest Method:POSTStatus Code:200 OKRemote Address:220.181.76.84:80Referrer Policy:no-referrer-when-downgradeResponse Headers:Connection:keep-aliveContent-Encoding:gzipContent-Type:application/json; charset=utf-8Date:Fri, 02 Mar 2018 02:18:25 GMTServer:nginxSet-Cookie:YOUDAO_MOBILE_ACCESS_TYPE=0; domain=.youdao; expires=Sat, 02-Mar-2019 02:18:25 GMTTransfer-Encoding:chunkedVary:Accept-EncodingRequest Headers:Accept:application/json, text/javascript, */*; q=0.01Accept-Encoding:gzip, deflateAccept-Language:zh-CN,zh;q=0.9Connection:keep-aliveContent-Length:205Content-Type:application/x-www-form-urlencoded; charset=UTF-8Cookie:OUTFOX_SEARCH_USER_ID_NCOO=901526923.248523; _ntes_nnid=d2c9f3c0ad87edc2a18d8baf7493468a,1489816879253; P_INFO=sijipingzaojia@126|1507340542|0|other|00&99|shd&1506756788&other#shd&370100#10#0#0|&0||sijipingzaojia@126; OUTFOX_SEARCH_USER_ID=1202025429@123.58.182.244; _ga=GA1.2.1223743331.1511144818; _ym_uid=1517990399796278715; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abce35wgNPW3r7TqipGhw; __lnkrntdmcvrd=-1; ___rl__test__cookies=1519957105235Host:fanyi.youdaoOrigin::/?keyfrom=dict2.topUser-Agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36X-Requested-With:XMLHttpRequestQuert String Parameyters:smartresult:dictsmartresult:ruleForm Data:i:hellofrom:AUTOto:AUTOsmartresult:dictclient:fanyideskwebsalt:1519957105239sign:8576918dd13c8c792aabc6986380a8bbdoctype:jsonversion:2.1keyfrom:fanyi.webaction:FY_BY_CLICKBUTTIONtypoResult:false
"""

根据上面拦截到的信息,拼装自己的请求,然后发送:

def doDict(keyword):headers = {'Accept': 'application/json, text/javascript, */*; q=0.01',"Connection": "keep - alive",'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8','User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36','Host': 'fanyi.youdao','Origin': 'http: // fanyi.youdao','Referer': '/?keyfrom=dict2.top','X-Requested-With': 'XMLHttpRequest','Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=901526923.248523; _ntes_nnid=d2c9f3c0ad87edc2a18d8baf7493468a,1489816879253; P_INFO=sijipingzaojia@126|1507340542|0|other|00&99|shd&1506756788&other#shd&370100#10#0#0|&0||sijipingzaojia@126; OUTFOX_SEARCH_USER_ID=1202025429@123.58.182.244; _ga=GA1.2.1223743331.1511144818; _ym_uid=1517990399796278715; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abce35wgNPW3r7TqipGhw; __lnkrntdmcvrd=-1; YOUDAO_MOBILE_ACCESS_TYPE=0; ___rl__test__cookies=1519960368231',}req = request.Request("=dict&smartresult=rule", headers=headers)data = {'i': keyword,'from': 'AUTO','to': 'AUTO','smartresult': 'dict','client': 'fanyideskweb','salt': '1519960368238','sign': '1078dab49931bac7081851a7da7320b2','doctype': 'json','version': '2.1','keyfrom': 'fanyi.web','action': 'FY_BY_CLICKBUTTION','typoResult': 'false',}encode_data = bytes(parse.urlencode(data), encoding='utf-8')response = request.urlopen(req, data=encode_data)print(response.read().decode('utf-8'))if __name__ == '__main__':keyword = input("请输入要翻译的单词:")doDict(keyword)

输入”hello”,运行结果为:

{"translateResult":[[{"tgt":"你好","src":"hello"}]],"errorCode":0,"type":"en2zh-CHS","smartResult":{"entries":["","n. 表示问候, 惊奇或唤起注意时的用语\r\n","int. 喂;哈罗\r\n","n. (Hello)人名;(法)埃洛\r\n"],"type":1}}

so,这样就完成了一个简单的post请求。
不过上述代码只对”hello”有效,因为form参数中有sign签名校验,目前还不知道怎么破解,不过这也难不倒我们,后续我们会介绍如何从爬到的HTML中获取我们关心的数据信息。

urllib库的基本使用和参数介绍就到这了,休息,休息一下~

更多推荐

03—小白学Python爬虫之urllib的基本和进阶使用及Get、Post示例

本文发布于:2024-03-23 18:22:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1741335.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:进阶   爬虫   示例   小白学   Python

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!