Python3爬虫技术文档(一)—— HTML数据的获取

Jenny ·
更新时间:2024-11-11
· 554 次阅读

目录使用urlib发送请求处理异常解析链接分析Robots协议使用requests基本用法高级用法
爬虫首先是需要获取某个网页的源代码,从而才能获取你想要的信息。
当主机向网站服务器发送一个请求,服务器返回的就是网页的源代码。同时在网页中鼠标右击 —>查看网页源代码 即可看见当前网页中的源代码。但是,并不是说页面呈现给你什么内容,源代码里就会出现什么内容。部分内容是采用JS或者PHP等服务器脚本动态从数据库中获取并渲染到页面上的,所以,经常在源代码中看到本来应该是数据的地方是一个JS代码或者只有一个
块。当然,可以通过其他方法获取源代码。
下面介绍几种获取网页源代码的方式 使用urlib

urlib是Python内置的HTTP请求库,它包含以下4个模块:

发送请求

request
它是最基本的HTTP请求模块,可以用来模拟发送请求,只需要给库方法传入URL以及其他参数,就可以模拟发送请求。
1. urlopen()
urllib.request模块提供了最基本的构造HTTP请求的方法。利用urlopen()可以模拟浏览器的一个请求发起过程,同时它还可以处理授权验证、重定向、浏览器Cookies等。

import urllib.request response = urllib.request.urlopen('https://www.csdn.net/') print(response.read().decode('utf-8'))

运行结果如下图所示:
在这里插入图片描述
这是最基本的urlopen()的用法,我们还可以添加data参数。首先看一下urlopen()函数的API:

urllib.request.urlopen(url, data-None, [timeout, ]*, cafile=None, cadafault=False, context=None)
参数 用法
data 可选,如果添加该参数,并且它是bytes类型,则需要通过bytes()方法转化。另外,如果传递这个参数,它的请求方式变为POST方式
timeout 可选,用于设置超时时间,单位为秒,它支持HTTP、HTTPS、FTP请求
其他参数 context参数,必须是ssl.SSLContext类型,用来指定SSL设置;cafile和capath分别指定CA证书和它的路径。

2. request

import urllib.request request = urllib.request.Request('https://python.org') respomse = urllib.request.urlopen(request) print(response.read().decode('utf-8'))

首先我们看下request的API:

class urllib.request.Request(url,data=None, headers={}, origin_req_host=None, unverifiable=False, method=None) 第一个参数url用于请求URL,这是必传参数,其他都是可选参数。 第二个参数data必须传bytes(字节流)类型的。如果它是字典,可以先用urllib.parse模块里的**urlencode()**编码 第三个参数headers是一个字典,它是请求头,可以在构造请求时通过headers参数直接构造,也可以通过调用请求实例的add_header()方法添加。
添加请求头最常用的用法就是通过修改
User-Agent
来伪装浏览器,默认的User-Agent是Python-urllib,我们可以通过修改它来伪装浏览器。 第四个参数orgin_req_host指的是请求方的host名称或者IP地址 第五个参数unverifiable表示这个请求是否是无法验证的,默认是False 第六个参数method是一个字符串,用来指示请求使用的方法 from urllib import request, parse url = 'http://httpbin.org/post' headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host': 'httpbin.org' } dict = { 'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf-8') req = request.Request(url=url, data=data, headers=headers, method='POST') response = request.urlopen(req) print(response.read().decode('utf-8'))

这里用4个参数构造了一个请求,其中url请求URL,headers中指定了User-Agent和Host,参数data用urlencode()和bytes()方法转成字节流,还指定了请求方式为POST
运行结果:
在这里插入图片描述
3. 高级用法 Handler工具

(1) Handler工具
首先,urllib.request模块里的BaseHandler类是所有其他Handler的父类。
接下来,有各种Handler子类继承这个BaseHandler类

HTTPDefaultErrorHandler:用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常。 HTTPRedirectHandler:用于处理重定向。 HTTPCookieProcessor:用于处理Cookies。 ProxyHandler:用于设置代理,默认代理为空。 HttppassordMgr:用于管理密码,它维护了用户名和密码的表。 HTTPBasicAuthHandler:用于管理认证。

还有其他的类,详情可参考官方文档:https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler

(2) OpenerDirector类
简称为Opener。Opener可以使用open()方法,返回类型和urlopen()一致。我们可以使用Handler构建Opener。

验证:使用HTTPBasicAuthHandler就可以完成。

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener from urllib.error import URLError username = 'username' password = 'passowrd' url = 'http://localhost:5000/' p = HTTPPasswordMgrWithDefaultRealm() p.add_password(None, url, username, password) auth_handler = HTTPBasicAuthHandler(p) opener = build_opener(auth_handler) try: result = opener.open(url) html = result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)

首先实例化HTTPBasicAuthHandler对象,参数是HTTPPasswordMgrWithDefaultRealm对象,它利用add_password()添加用户名和密码,这样既建立了一个处理验证的Handler。
接下来,利用这个Handler并使用build_opener()方法构建一个Opener。
然后利用Opener的open()方法打开链接。

代理

from urllib.error import URLError from urllib.request import ProxyHandler, build_opener proxy_handler = ProxyHandler({ 'http':'http://127.0.0.1:6564', 'https':'https://127.0.0.1:6594' }) opener = build_opener(proxy_handler) try: response = opener.open('https://www.baidu.com') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)

这里在本地搭建了一个代理。运行在6564端口上。这里使用ProxyHandler,参数是一个字典,键名是协议类型,键值是代理链接,可添加多个代理。然后,利用这个Handler以及build_opener()方法构造一个Opener,之后发送请求

Cookies
(1)获取网站Cookie

import http.cookiejar, urllib.request cookie = http.cookiejar.CookieJar() handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') for item in cookie: print(item.name + "=" + item.value)

运行结果
在这里插入图片描述
(2)保存网站Cookies

import http.cookiejar, urllib.request filename = 'cookies.txt' cookie = http.cookiejar.MozillaCookieJar(filename=filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') cookie.save(ignore_discard=True, ignore_expires=True)

MozillaCookieJar是CookieJar的子类,可以用来处理Cookies和文件相关事件。
运行之后,生成一个cookies.txt文件,内容如下:
在这里插入图片描述
LWPCookieJar同样可以读取和保存Cookies,但是格式不同。

cookie = http.cookiejar.LWPCookieJar(filename)

运行结果:
在这里插入图片描述

(3)读取Cookies

import http.cookiejar, urllib.request cookie = http.cookiejar.LWPCookieJar() cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') print(response.read().decode('utf-8'))

这里使用load()方法读取本地Cookies文件,获取到内容后构建Handler和Opener得到百度网页的源代码。

error
异常处理模块,若出现请求错误,可以捕获这些异常,然后进行重试或者其他操作,从而防止程序意外终止。
parse
工具模块,提供处理URL的方法。
robotparser
识别网站的robots.txt文件,判断网站是否允许爬取。

处理异常

urllib的errow模块定义了由request模块产生的异常。如果出现异常,request模块会抛出error模块中定义的异常
(1)URLError
URLError类来自urllib库的error模块,继承自OSError类。是error异常模块的基类。
它有一个属性reason,返回错误的原因

from urllib import request, error try: response = request.urlopen('https://cuiqingcai.com/index.htm') except error.URLError as e: print(e.reason)

运行结果:Not Found
(2)HTTPError
是URLError的子类,处理HTTP请求错误。它有以下三个属性:

code:返回HTTP状态码 reason:返回错误的原因 headers:返回请求头 from urllib import request, error try: response = request.urlopen('https://cuiqingcai.com/index.htm') except error.HTTPError as e: print(e.reason) print(e.code) print(e.headers)

运行结果:
在这里插入图片描述
异常处理写法:

from urllib import request, error try: response = request.urlopen('https://cuiqingcai.com/index.htm') except error.HTTPError as e: print(e.reason) print(e.code) print(e.headers) except error.URLError as e: print(e.reason) else: print('Resquest Successfully') 解析链接

1. urlparse()
这个方法可以实现URL的识别和分段

from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html;user?id=5#comment') print(type(result), result)

运行结果如下:

ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')

这里利用urlparse()方法进行了一个URL解析。输出了解析结果类型,之后输出结果。
返回的结果是一个ParseResult类型的对象,包含6个部分,scheme、netloc、path、params、query和fragment。
则一个标准的链接格式为:

scheme://netloc/path;params?query#fragment

urlparse()函数API:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True) urlstring:必选,待解析的URL scheme:默认的协议。 allow_fragments:是否忽略fragment。

(2)urlunparse()
接受的参数是可迭代对象,长度必须为6。

from urllib.parse import urlunparse data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment'] print(urlunparse(data))

运行结果:
在这里插入图片描述

(3)urlsplit()
和urlparse()相似,但是不单独解析params这个部分,只返回5个结果
(4)urlunsplit()
和urlunparse()相似,但是长度必须为5
(5)urljoin()
两个参数,base_url和新的链接。方法会分析base_url的scheme、netloc和path,这3个内容并对新链接缺失的部分进行补充。
(6)urlencode()
构造GET请求

from urllib.parse import urlencode params = { 'name':'germey', 'age':22 } base_url = 'http://baidu.com?' url = base_url + urlencode(params) print(url)

运行结果:
在这里插入图片描述
(7)parse_qs()
利用parse_qs()方法,可以将GET请求参数转化为字典。

from urllib.parse import parse_qs query = 'name=germey&age=22' print(parse_qs(query))

运行结果:
在这里插入图片描述

(8)parse_qsl()
它用于将参数转化为元祖组成的列表。

from urllib.parse import parse_qsl query = 'name=germey&age=22' print(parse_qsl(query))

运行结果;
在这里插入图片描述

(9)quote()
此方法可以将内容转化为URL编码的格式。例如,可以将中文字符转化为URL编码。

from urllib.parse import quote keyword = '中文' url = 'https://www.baidu.com/s?wd=' + quote(keyword) print(url)

运行结果:
在这里插入图片描述

(10)unquote()
他可以进行URL解码。

from urllib.parse import unquote url = 'https://www.baidu.com/s?wd=%E4%B8%AD%E6%96%87' print(unquote(url))

运行结果:
在这里插入图片描述

分析Robots协议

1. Robots协议
Robots协议也称作爬虫协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,通常是一个robots.txt的文本文件。当访问一个站点时,首先会检查站点根目录下是否存在robots.txt文件,如果存在,则爬虫会根据其中定义的爬取范围来爬取,如果没有找到文件,则会访问所有可能直接访问的页面。
robots.txt文件:

User-agent: * Disallow: / Allow: /public/

则搜索爬虫只允许爬取public目录。

User-agent描述了搜索爬虫的名称,这里为*则代表该协议对任何爬取爬虫都有效。但是至少要指定一条规则。 Disallow指定了不允许爬取的目录 Allow一般和Disallow一起使用,用来排除某些限制。

2. 爬虫名称

爬虫名称 名称 网站
BaiduSpider 百度 www.baidu.com
Googlebot 谷歌 www.google.com
360Spider 360搜索 www.so.com
YodaoBot 有道 www.youdao.com
ia_archiver Alexa www.alexa.com
Scooter altavista www.altavista.com

3. robotparser

robotparser模块提供了一个类RoobotFileParser,它可以根据某网站的robots.txt文件来判断一个爬取爬虫是否有权限来爬取这个网页。
只需要在构造方法里传入robots.txt的链接即可使用。它的声明如下;

urllib.robotparser.RobotFileParser(url='')

也可以不传入,之后使用set_url()方法设置即可
以下是这个类常用的方法:

set_url():用来设置robots.txt文件的链接。若在创建RobotFileParser对象时传入了链接,就不需要用这个方法设置了。 read():读取robots.txt文件,并进行分析。 parse():解析robots.txt can_fetch():传入两个参数,第一个是User-agent,第二个是抓取的URL,返回的是该搜索引擎是否可以抓取这个URL,True或False。 mtime():返回上次抓取和分析robots.txt的时间。 modified():同样对长时间分析和抓取的搜索爬虫有帮助,将当前时间设置为上次抓取和分析robots.txt的时间。 使用requests 基本用法

1. requests库安装
requests库是第三方库,需要安装。

Win:pip install requests Linunx:sudo pip3 install requests

2. requests实例

import requests r = requests.get('https://www.baidu.com/') print(type(r)) print(r.status_code) print(type(r.text)) print(r.text) print(r.cookies)

运行结果:
在这里插入图片描述
这里的get()方法实现与urlopen()一致,得到一个Response对象,然后分别输出Response类型,状态码,响应体的类型,内容以及Cookies。

3. GET请求

实例: import requests r = requests.get('http://httpbin.org/get') print(r.text)

运行结果:
在这里插入图片描述
这个网站会判断客户端发起的是否是GET请求,如果是,则返回相应的请求信息。
返回结果中包含请求头、URL、IP等信息。
GET请求中往往会添加额外的信息。这里我们使用字典来存储:

import requests data = { 'name':'germey', 'age':22 } r = requests.get('http://httpbin.org/get', params=data) print(r.text)

运行结果;
在这里插入图片描述
通过返回内容可以判断,请求链接自动构造成了:

http://httpbin.org/get?age=22&name=germey

网页返回的类型是str类型,是JSON格式,如果想要解析返回结果,得到一个自己单格式的话,可以直接调用json()方法:

import requests r = requests.get('http://httpbin.org/get') print(type(r.text)) print(r.json()) print(type(r.json))

运行结果:
在这里插入图片描述

抓取网页 import requests import re headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36' } r = requests.get('https://www.zhihu.com/explore', headers=headers) print(r.text)

运行结果:
在这里插入图片描述

抓取二进制数据
图片、音频、视频等文件本质上都是由二进制码组成的,如果我们要看到这些多媒体文件,我们就要获取到它们的二进制码。 import requests r = requests.get("https://github.com/favicon.ico") print(r.text) print(r.content)

运行结果:
在这里插入图片描述
r.text发生了乱码,r.content结果前有个b,表示bytes类型的数据。
我们将刚才提取到的内容保存下来:

import requests r = requests.get("https://github.com/favicon.ico") with open('favicon.ico','wb') as f: f.write(r.content)

运行结果:
在这里插入图片描述
这里使用了open()方法,第一个参数是文件名称,第二个参数代表以二进制写的形式打开,可以向文件中写入二进制数据。
同样,音频也可以这样获取。

添加headers
上面例子中添加了headers和User-Agent信息,才能访问。

4. POST请求

import requests data = {'name':'germey', 'age':'22'} r = requests.post('http://httpbin.org/post', data=data) print(r.text)

运行结果:
在这里插入图片描述

高级用法

1. 文件上传

import requests files = {'file':open('favicon.ico', 'rb')} r = requests.post('http://httpbin.org/post', files=files) print(r.text)

运行结果:
在这里插入图片描述

2. Cookies

import requests r = requests.get('https://www.baidu.com') print(r.cookies) for key, value in r.cookies.items(): print(key + '=' + value)

运行结果:
在这里插入图片描述

先调用cookies属性即可得到Cookies,它是RequestCookieJar类型。然后使用items()方法将其转化为元祖组成的列表,遍历输出每一个Cookies的名称和值。

3. 会话维持
requests中每次请求都是相当于打开新的浏览器,如果是要获取登录后的个人信息,则需要先获取登录后的Cookies,然后通过Cookies进入获取信息。解决这个问题的方法是通过维持同一个会话,即只打开一个浏览器选项卡:Session对象

import requests requests.get('http://httpbin.org/cookies/set/number/123456789') r = requests.get('http://httpbin.org/cookies') print(r.text)

运行结果:
在这里插入图片描述
我们请求这个网址时,设置了一个cookies,名称叫做number,内容为123456789,随后又请求了网址,获取当前的Cookies。但是,并没有获取到。
使用Session:

import requests s = requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') r = s.get('http://httpbin.org/cookies') print(r.text)

运行结果:
在这里插入图片描述
成功获取!

4. 代理设置
当爬取某个网站的时候,如果大规模爬取,会弹出验证码或者跳转到登录验证界面,甚至会封禁客户端IP,为了避免这个情况,我们可以使用代理来解决这个问题,这里使用proxies参数

import requests proxies = { 'http':'http://10.10.1.10:3128', 'https':'https://10.10.1.10:1080', } request.get('https://www.baidu.com', proxies=proxies)

5. 超时设置
在网络不好或者服务器网络响应缓慢甚至无响应时,我们可能会等很久时间才能得到响应,甚至是无响应。为了防止出现这种情况,我们可以设置timeout参数

import requests r = requests.get('https://www.taobao.com', timeout = 1) print(r.status_code)

这里设置超时时间为1秒,如果超出1秒未响应,则会抛出异常。

6. 身份认证
在访问网站时,我们可能会遇见认证界面,那么可以使用requests自带的身份认证功能:

import requests from requests.auth import HTTPBasicAuth r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'passowrd')) print(r.status_code)

如果用户名和密码正确,则会返回200状态码。如果失败,返回401状态码。
也可以使用下面的方法:

import requests r = requests.get('http://localhost:5000', auth=('username', 'passowrd')) print(r.status_code)

更详细的功能可以参考requests_oauthlib的官方文档:https://requests-oauthlib.readthedocs.org/

下一篇博客讲解非HTML网页如何爬取 Thanks♪(・ω・)ノ


作者:小昱同学



技术文档 HTML Python3 Python 爬虫

需要 登录 后方可回复, 如果你还没有账号请 注册新账号