首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

网络爬虫-进阶篇-第一阶

上一节我们讲解了python网络爬虫的基础,包括http、https、网络的请求和响应原理、以及Cookie和会话、爬虫原理等内容。本节课我们开始讲解基本库的使用。

首先我们来了解一下urllib库,这个库是python内置的HTTP请求库,不需要额外安装。

Urllib一共包含四个模块:

1.request:最基本的HTTP请求模块,可以用来模拟发送请求

2.error:异常处理模块,如果程序执行过程中出现请求错误,我们可以捕获这些异常,然后进行重试或者其他操作以保证程序不会意外终止。

3.parse:一个工具模块,提供了许多URL处理方法,如:拆分、合并、解析URL

4.robotparse:用来识别网站的robot.txt文件,进而判别哪些网站可以爬取

发送请求:使用urllib的request模块,我们能够发送请求并得到响应。

具体方法:

1.urlopen()方法

urllib.request模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时还带有处理授权验证、重定向、浏览器Cookie以及其他内容。

示例代码:

import urllib.requestimport urllib.parseresponse = urllib.request.urlopen('http://python.org',timeout=10)print(type(response))print(response.read().decode('utf-8'))print(response.status)print(response.getheaders())

运行结果:

网页源代码(篇幅过长,在pycharm中进行演示)

200

[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('x-xss-protection', '1; mode=block'), ('X-Clacks-Overhead', 'GNU Terry Pratchett'), ('Via', '1.1 varnish'), ('Content-Length', '48940'), ('Accept-Ranges', 'bytes'), ('Date', 'Sat, 12 Jan 2019 10:44:58 GMT'), ('Via', '1.1 varnish'), ('Age', '2081'), ('Connection', 'close'), ('X-Served-By', 'cache-iad2131-IAD, cache-bur17539-BUR'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '1, 286'), ('X-Timer', 'S1547289899.552402,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]

此代码中利用最基本的urlopen()方法,完成了最基本的简单网页的GET请求抓取,response为网页返回的响应,运用了type()方法来输出响应的类型,即http.client.HTTPResponse的类对象,主要包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、 status、reason、gebuglevel、closed等属性。

通过read()方法可以得到返回的网页内容,而status属性是返回结果的状态码(网页状态码),正如上节课讲解的200代表请求成功,404代表网页未找到,而response对象的getheaders()方法则是用来显示响应头信息的,也可用getheader()传递相应的参数返回对应的值。

urlopen()函数的API:

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

我们可以发现第一个url是必须传递的参数,后面的参数都是可以传或者是不传的,我们称之为默认参数。下面我们来简单介绍一下这些参数:

data(附加参数):

data参数是可选的,如果要添加该参数,需要用bytes()方法将参数转化为字节流编码格式的内容,即bytes类型的内容,此外,如果传递了这个参数,则它的请求方式就不再是GET方式,而是POST方式。

示例代码

import urllib.requestimport urllib.parsedata = bytes(urllib.parse.urlencode({'name':'wwg'}),encoding='utf-8')response = urllib.request.urlopen('http://httpbin.org/post',data=data)print(response.read())

运行结果:

b'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "name": "wwg"\n }, \n "headers": {\n "Accept-Encoding": "identity", \n "Connection": "close", \n "Content-Length": "8", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "User-Agent": "Python-urllib/3.6"\n }, \n "json": null, \n "origin": "120.193.252.124", \n "url": "http://httpbin.org/post"\n}\n'

我们传递的参数是一个字典{‘name’:’wwg’},而bytes()方法的第一个参数需要是字符串类型,所以先调用了urllib.parse.urlencode()方法将字典转化为字符串,再调用bytes()方法转化为bytes(字节流)类型。此外我们要注意代码中的请求站点为http://httpbin.org,这个网站是测试http请求的网站,可以用来测试HTTP请求和响应的各种信息,比如Cookie、ip、headers和登录验证等等,且支持GET、POST等多种方式,对Web开发和测试很有帮助。我们可以看到我们传递的参数出现在了form字段中,就是提交的表单。

timeout参数:

timeout参数用于设置超时时间,单位为秒,意思就是如果请求超过了这个设置时间,还没有得到响应,就会抛出异常。

其他参数:

context参数必须是

ssl.SSLContext类型,用来指定SSL设置,此外cafile和capath两个参数用于指定CA认证书和它的路径,在请求HTTPS链接时会有用。cadefault参数已经弃用了,其默认值为false。

2.Request类

利用urlopen方法可以实现最简单的基本请求,很多时候如果我们不添加请求头伪装成浏览器,网站会禁止我们爬取,如果请求中需要加入Headers等信息,就可以用更强大的Request类来构建。

Request类的API:

urllib.request.Request(url,data=None,headers={ },orgin_req_host,unveriable=False,method=None)

第一个参数url用于请求URL,是必传的参数。

第二个参数data是可选参数,如果要传必须是bytes类型的,如果是字典还要调用urllib.parse.urlencode()方法进行编码。

第三个参数是headers(请求头)是一个字典,可以直接给headers传递参数或者通过add_header()方法进行添加

添加请求头中最常用的方法就是通过修改User-Agent来伪装成浏览器,默认的User-Agent是Python-urllib。

第四个参数origin_req_host指的是请求方的host名称或者IP地址

第五个参数unverfiable表示这个请求是否无法验证,默认是False,意思就是说用户没有足够的权限来选择接收这个请求的结果。

第六个参数method是一个字符串,用来指示请求使用的方法,常见的有GET、POST等。

示例代码:

import urllib.requestimport urllib.parseurl = 'http://httpbin.org/post'headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36','Host': 'httpbin.org'}dict={'name':'wwg'}data = bytes(urllib.parse.urlencode(dict),encoding='utf-8')request = urllib.request.Request(url,headers=headers,data=data,method='POST')response = urllib.request.urlopen(request)print(response.read().decode('utf-8'))

运行结果:

3.高级用法(Cookie处理、代理设置等)

我们需要用到强大的处理器Handler,我们可以理解为用于各种场合的处理器,有专门用于处理登录验证的,有专门用于处理Cookies的,有处理代理设置的,利用这些处理器我们可以做请求中所有的事。

首先介绍一下urllib.request模块里的BaseHandler类,它是所有其他Handler的父类,它提供最基础的方法,例如

default_open()、protocal_request()等

继承BaseHandler用于各种情形中的Handler:

1.HTTPDefaultErrorHandler:用于处理HTTP响应错误,错误都会抛出HTTPError类型

2.HTTPRedirectHandler:用于处理重定向

3.HTTPCookieProcessor:用于处理Cookie

4.ProxyHandler:用于设置代理,默认代理为空

5.HTTPBasicAuthHandler:用于管理验证,如果打开一个链接时需要认证,那么其用来解决认证问题

6.HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表

此外还有一个很重要的类是OpenerDirector类,我们可以称为Opener。我们在使用urllib()这个方法的时候,实际上就是urllib为我们提供的一个Opener

Opener概念的引入是为了实现更高级的功能,之前使用的Request和urlopen()相当于类库为我们封装好了常用的请求方法,但是只能完成基本的请求,但是如果想要实现更高级的功能,我们需要使用更底层的实例来完成操作,所以用到了Opener。

Opener可以使用open()方法,返回类型和urlopen一致,而Opener就是用Handler来构造的,简而言之,Opener就是具有Handler功能的操作对象。

Opener是一个具有多个高级功能的对象,其具有的open方法和urlopen方法具有相同的功能,但是Opener本身具有更多高级功能

1.验证

很多时候当我们输入一个网站进行回车之后网页会弹出一个提示框,需要我们进行登录,那么在爬虫程序运行的时候首先也会要求登录,这个登录的过程我们就可以使用具有登录验证功能的Handler来完成。

示例代码:

from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_openerfrom urllib.error import URLErrorusername = 'uesrname'password = 'password'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)

代码解读:p为

HTTPPasswordMgrWithDefaultRealm的一个实例化对象,用于保存用户名和密码,以便在登录网站时验证,下一步就是构建具有验证功能的Handler(处理器),

HTTPBasicAuthHandler用于管理验证,即auth_handler用于处理验证,创建Handler后要根据Handler创建opener,这个opener具有Handler的功能,使用build_opener构建opener,这个opener在发送请求时就会自动验证,使用open()方法打开链接。

2.代理

基本概念:我们在做爬虫过程中可能会遇到一种情形,起初爬虫正常运行,抓取数据,但是过了不久就会出现错误,比如403Forbidden,此时打开网页一看,可以看到“您的IP访问频率太高”类似于这样的提示。这种现象出现的原因是网站采取了一些反爬虫措施,比如服务器会检测某个IP在单位时间内的请求次数,如果超过了设定的访问频率,就会直接拒绝服务,返回一些错误信息,我们成为“封IP”。

所以就衍生了一种伪装我们的IP从而让服务器识别不出是由我们本机发起的请求,从而来防止IP被封,一种有效的实现方式就是代理。

代理实际上指的就是代理服务器,英文名叫作proxy server,它的功能是代理网络用户去取得网络信息,通俗地说就是网络信息中转站。在我们正常请求网站时,是发送请求给Web服务器,Web服务器再把响应回传给我们。如果设置了代理服务器,时间上就是在本机和服务器之间搭建了一个信息中转地带,本机不再之间向Web服务器发送请求,而是通过向代理服务器发送请求,再由代理服务器发送给Web服务器,接着又代理服务器把Web服务器返回的响应转发给本机的方式完成请求。这个过程中Web服务器识别出的真实IP不是本机的IP,从而实现了IP伪装。我们说科学上网中搭梯子就是用的这个原理,通过代理(海外)服务器向google、youtube等网站发送请求,再由代理服务器回传响应,绕过中国防火墙,进而浏览国外的网站。

示例代码:

from urllib.error import URLErrorfrom urllib.request import ProxyHandler,build_openerproxy_handler = ProxyHandler({

'http':'127.0.0.1:9743','https':'127.0.0.1:9743'})opener = build_opener(proxy_handler)try:response = opener.open('http://www.baidu.com')print(response.read().decode('utf-8'))except URLError as e:print(e.reason)

这个ProxyHandler的参数是字典,键名是协议类型,键值是代理链接,可以添加多个代理。

3.Cookie

获取网站的Cookie

示例代码:

import http.cookiejar,urllib.requestcookie = http.cookiejar.CookieJar()

handler = urllib.request.HTTPCookieProcessor(cookie)

opener = urllib.request.build_opener(handler)

response = opener.open('http://www.baidu.com')filename = 'F:\\cookies.txt'cookie = http.cookiejar.MozillaCookieJar(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)cookie.load('F:\\cookies.txt',ignore_expires=True,ignore_discard=True)print(cookie)

代码解读:首先构造了cookie,cookie为CookieJar对象,用于存储cookie的值,每一个元素就是一个cookie的元素和对应的值,以name和value形式存储,接下来便是构造具有Cookie处理功能的Handler,下一步便是构造具有cookie处理功能的opener,

实际上cookie是以文本形式进行存储的,我们也可以将cookie保存到文本中,此时需要将CookieJar换成MozillaCookieJar,在生成文件时使用,是CookieJar的子类,可以用来处理Cookie和文件相关的事件,例如读取和保存Cookie。save()方法可以保存cookie的值,若要从文件中读取cookie的值需要使用load()方法。我们上节课说过,读取cookie的原因就是维持会话跟踪,在下一次发送请求时带上cookie。运行代码后我们就会发现F盘下新增了一个名cookie.txt的文件,其内容为:

这是保存为Mozilla型浏览器Cookies格式,LWPCookieJar也可以做到读取和保存Cookie,但是保存的格式和MozillaCookieJar不同,会保存成LWP格式的文件,只需将

cookie=http.cookiejar.MozillaCookieJar(filename)改成cookie=http.cookiejar.LWPCookieJar(filename)

本节课我们就说到这里,下节课我们继续介绍有关处理异常、解析链接和分析Robots协议的问题。

文案:王为广

排版:谢传彪

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190117B1EK9900?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券