Python网络爬虫(一)

Urllib发送请求

基本用法

基本的用法就是调用request库,
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)在编写代码之前把这些属性值填写成自己想要的参数就行了,

高级用法

将介绍“处理器“---Handler。利用它就可以处理Cookies、设置代理等任何HTTP请求中所有的事情。
首先介绍下 urllib.request 模块里的 BaseHandler类,它是所有其他 Handler 的父类,它提供了最基本的 Handler 的方法,例如 default_open()、protocol_request() 方法等。接下来就有各种 Handler 子类继承这个 BaseHandler 类,举例几个如下:

  • HTTPDefaultErrorHandler 用于处理 HTTP 响应错误,错误都会抛出 HTTPError 类型的异常。
  • HTTPRedirectHandler 用于处理重定向。
  • HTTPCookieProcessor 用于处理 Cookies。
  • ProxyHandler 用于设置代理,默认代理为空。
  • HTTPPasswordMgr 用于管理密码,它维护了用户名密码的表。
  • HTTPBasicAuthHandler 用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。
    更多的Handler可以参考https://docs.python.org/3/library/urllib.request.html#basehandler-objects
    在正常的request中需要使用urlopen,而handler则是需要使用Opener,urlopen()这个方法就是Urllib为我们提供的一个Opener。

认证

有些网站必须要输入用户名和密码,认证成功后才能继续显示。类似的网站比如路由器的管理员登录界面(在浏览器中输入192.168.1.1跳转的界面)。在这里并不是绕过登录界面,而是在模拟请求的时候不会报错。

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = 'username'
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)

代理

设置代理

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
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)

首先花点时间介绍一下Cookies,登录网站的时候我们常常会发现有些网站自动登录了,而且很长时间都不会失效、有些则是需要我们重新登录(输入用户模型和密码的),这其实涉及到了Session和Cookies的相关知识。HTTP协议是一种无状态的协议,意思是客户端与服务端进行数据交互的时候并不会保存进行的操作,举个例子:当我们加载网页的一张图片,传过来只有半张时停止加载,我们如果不加处理的再去向服务器请求,服务端是不会记住之前传输的操作的,服务端所进行的操作是重新将这张图片完整的数据重新传输一次。所以,HTTP 的无状态是指 HTTP 协议对事务处理是没有记忆能力的,也就是说服务器不知道客户端是什么状态。。这点虽然避免了信息的冗余性(不会要求HTTP协议在进行数据传输时仍然要保存事务处理),但是对于需要用户登录的页面来说,为了保持前后状态,我们肯定不希望将前面的请求全部重传一次,这样过于浪费资源了,所以保持HTTP连接状态的技术就出现了。Session在服务端(网站的服务器),用于保存用户的会话信息,Cookies在客户端。服务器通过识别 Cookies 并鉴定出是哪个用户,然后再判断用户是否是登录状态,然后返回对应的 Response。所以,我们可以这样理解:如果我们将一次登陆成功后的Cookies放在Request Headers里面直接请求服务端,就不必重新模拟登陆了。
当浏览器下一次再请求该网站时,浏览器会把此Cookies 放到 Request Headers 一起提交给服务器,Cookies 携带了 Session ID 信息,服务器检查该 Cookies 即可找到对应的 Session 是什么,然后再判断 Session 来以此来辨认用户状态。所以我们在登录某个网站的时候,登录成功后服务器会告诉客户端设置哪些 Cookies 信息,在后续访问页面时客户端会把 Cookies 发送给服务器,服务器再找到对应的 Session 加以判断,如果 Session 中的某些设置登录状态的变量是有效的,那就证明用户是处于登录状态的,即可返回登录之后才可以查看的网页内容,浏览器进行解析便可以看到了。
好了,下面我们介绍python中与Cookies相关的Handler,首先将网站的Cookies获取下来:

import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()    #申明一个CookieJar对象
handler = urllib.request.HTTPCookieProcessor(cookie) #创建Handler
opener = urllib.request.build_opener(handler)   #构建出Opener
response = opener.open('http://www.baidu.com')  #执行open()函数
for item in cookie:
    print(item.name+"="+item.value)

执行的结果如下:

BAIDUID=2E65A683F8A8BA3DF521469DF8EFF1E1:FG=1
BIDUPSID=2E65A683F8A8BA3DF521469DF8EFF1E1
H_PS_PSSID=20987_1421_18282_17949_21122_17001_21227_21189_21161_20927
PSTM=1474900615
BDSVRTM=0
BD_HOME=0

以上就是Cookies的完整样貌,我们可以将这个Cookie保存下来方便我们后面调用:

filename = 'cookies.txt'
#cookie = http.cookiejar.MozillaCookieJar(filename)
cookie = http.cookiejar.LWPCookieJar(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)

这时的 CookieJar就需要换成 MozillaCookieJar,生成文件时需要用到它,它是 CookieJar 的子类,可以用来处理 Cookies 和文件相关的事件,读取和保存 Cookies,它可以将 Cookies 保存成 Mozilla 型浏览器的 Cookies 的格式。
生成的cookies.txt文件如下:

#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="0CE9C56F598E69DB375B7C294AE5C591:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BIDUPSID=0CE9C56F598E69DB375B7C294AE5C591; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: H_PS_PSSID=20048_1448_18240_17944_21089_21192_21161_20929; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1474902671; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0

接下来利用Cookies的LWPCookieJar格式来读取文件:

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')

Urllib处理异常

在跑程序获取数据中,如果程序中途遇到错误而我们没有写异常处理的时候,尽可能辛辛苦苦跑的数据就损失了;在获取豆瓣电影top250的时候,部分电影的参数不完整,导致爬虫总是会在这中途出现错误。。。更有可能的是,如果网络情况突然变更,要做异常处理,是的网络恢复的时候能继续运行程序。综上,写异常处理真的非常重要!!

HTTPError

  • code,返回 HTTP Status Code,即状态码,比如 404 网页不存在,500 服务器内部错误等等。
  • reason,同父类一样,返回错误的原因。
  • headers,返回 Request Headers。
from urllib import request,error
try:
    response = request.urlopen('http://没有这个页面.com/index.htm')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers, seq='\n')
posted @ 2018-03-05 21:51  MrYun  阅读(189)  评论(0编辑  收藏  举报