urllib的基本使用

版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。 https://blog.csdn.net/wsmrzx/article/details/81591558

写在前面的话上一篇文章我们利用Chrome浏览器及其自带的开发者工具对网络爬虫的抓包过程作了一些初步的分析,以下我们将正式开始使用Python提供的HTTP请求库urllib走入网络爬虫世界的大门

温馨提示 :想要了解更规范的官方说明,可参考文档:https://docs.python.org/3.7/library/urllib.request.html

一、urllib简介

urllib是Python3自带的HTTP请求库,无需复杂的安装下载即可正常使用,十分适合爬虫入门使用

urllib中包含四个模块,其中最常用的莫过于request模块了,用于发送HTTP请求

模块 描述
urllib.request HTTP请求模块
urllib.parse URL解析模块
urllib.error 异常处理模块
urllib.robotparser robots.txt解析模块

二、urllib的基本使用

我们将通过urllib中最重要的一个函数 urllib.request.urlopen(url, data=None, [timeout, ] cafile=None, capath=None, cadefault=False, context=None) 贯穿学习urllib的初级使用方法,我们会由浅入深的对此函数进行拓展,从而一步步的了解urllib的使用技巧,并且结合具体的例子讲解以便于对其有更好的理解

以下我们选择 http://www.httpbin.org/ 作为测试网站,它提供了丰富的接口,能返回所发送的请求的相关信息,十分适合检查使用

1. 发送GET请求

>>> urllib.request.urlopen(url)

urllib.request.urlopen() 的第一个参数是 url ,url可以是一个字符串,用于指定目标网址的URL,值得注意的是,该方法返回的是一个 HTTPResponse 对象,其常用的属性方法列举如下

  • geturl():返回请求网站的URL
  • getcode():返回请求网站的状态码
  • getheaders():返回全部响应头信息
  • getheader(header):返回指定响应头信息
  • read():网站返回的响应体(bytes类型),通常需要使用 decode('utf-8') 将其转化为str类型
>>> import urllib.request
>>> response = urllib.request.urlopen("http://www.httpbin.org/get")

#查看response类型
>>> type(response)     
<class 'http.client.HTTPResponse'>

#返回请求网站的URL
>>> response.geturl()     
'http://www.httpbin.org/get'

#返回请求网站的状态码
>>> response.getcode()     
200

#返回全部响应头信息
>>> response.getheaders()     
[('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Date', 'Sat, 11 Aug 2018 01:39:14 GMT'), ('Content-Type', 'application/json'), ('Content-Length', '243'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true'), ('Via', '1.1 vegur')]

#返回指定响应头信息
>>> response.getheader('Connection')    
'close'

>>> response.read()     #查看网页源代码(bytes类型)
b'{\n  "args": {}, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Connection": "close", \n    "Host": "www.httpbin.org", \n    "User-Agent": "Python-urllib/3.6"\n  }, \n  "origin": "116.16.107.180", \n  "url": "http://www.httpbin.org/get"\n}\n'

>>> response.read().decode('utf-8')     #查看网页源代码(str类型)
'{\n  "args": {}, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Connection": "close", \n    "Host": "www.httpbin.org", \n    "User-Agent": "Python-urllib/3.6"\n  }, \n  "origin": "116.16.107.180", \n  "url": "http://www.httpbin.org/get"\n}\n'

2. 发送POST请求

>>> urllib.request.urlopen(url, data=None)

urllib.request.urlopen() 的第二个参数是 data ,当data参数没有被赋值时,则默认为None,使用GET请求方法发送请求(如上例),若希望使用POST方法发送请求时,则可以给data参数赋值,并在data中携带表单数据(bytes类型)

可以使用 urllib.parse.urlencode() 方法将dict类型数据转化成str类型数据
可以使用 encode('utf-8') 方法将str类型数据转化成bytes类型数据

>>> import urllib.request
>>> import urllib.parse

>>> url = 'http://www.httpbin.org/post'
>>> data = {
    'from':'AUTO',
    'to':'AUTO'
}
>>> type(data)
<class 'dict'>
>>> data = urllib.parse.urlencode(data)
>>> type(data)
<class 'str'>
>>> data = data.encode('utf-8')
>>> print(data)
<class 'bytes'>

>>> response = urllib.request.urlopen(url=url,data=data)
>>> html =  response.read().decode('utf-8')
>>> print(html)
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {      #其中这个就是我们所设定的表单数据
    "from": "AUTO", 
    "to": "AUTO"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Connection": "close", 
    "Content-Length": "17", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python-urllib/3.6"
  }, 
  "json": null, 
  "origin": "116.16.107.180", 
  "url": "http://www.httpbin.org/post"
}

3. 使用Request对象

>>> urllib.request.urlopen(req)

除了给 urllib.request.urlopen() 传入字符串表示URL之外,还可以传入一个 Request对象 来指定URL,此外,传入Request对象的另一个重要作用就是便于指定请求头部

我们知道,某些网站可能会首先检查请求头部中的 USER-AGENT 字段来判断该请求是否由网络爬虫程序发起,我们可以通过简单地修改 USER_AGENT 来绕过这一层检查,这里提供一个查找常用的 USER-AGENT 的网站:https://techblog.willshouse.com/2012/01/03/most-common-user-agents/

以下给出 Request对象 的原型:urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None),各参数意义说明如下:

  • url:请求网站的 URL
  • data:发送 POST 请求时提交的表单数据,默认为 None
  • headers:发送请求时附加的请求头部,默认为 {}
  • origin_req_host:请求方的 host 名称或者 IP 地址,默认为 None
  • unverifiable:请求方的请求无法验证,默认为 False
  • method:发送请求的方法,默认为 None
>>> import urllib.request

>>> url = 'http://www.httpbin.org/headers'
>>> headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
>>> req = urllib.request.Request(url, headers=headers, method='GET')

>>> response = urllib.request.urlopen(req)
>>> html = response.read().decode('utf-8')
>>> print(html)
{
  "headers": {
    "Accept-Encoding": "identity", 
    "Connection": "close", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"     #我们设定的USER-AGENT
  }
}

4. 设置超时时间

>>> urllib.request.urlopen(url, data=None, [timeout, ])

urllib.request.urlopen() 的第三个参数是 timeout,用来指定等待时间,若超过指定时间还没获得响应,则抛出一个异常。

我们可以使用 urllib.error 模块进行异常处理,其包含两个重要的类:URLErrorHTTPError,注意到 HTTPError 是 URLError 的子类,所以捕获异常时一般先要处理 HTTPError 异常,常用的格式如下:

import urllib.request
import urllib.error
import socket

>>> try:
    response = urllib.request.urlopen('http://www.httpbin.org/get', timeout=0.1)
except urllib.error.HTTPError as e:
    print("Error Code: ", e.code)
    print("Error Reason: ", e.reason)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('Time out')
else:
    print('Request Successfully')

Time out

5. 其他

对于 urllib.request.urlopen() 方法,我们还有几个参数没有提及,因为在实际情况中它们的应用比较少,所以在这里我们只是简单列举出它们的作用,详细用法请参考本文开头给出的官方链接

  • context 参数必须是一个 ssl.SSLContext 的实例,用于描述各种SSL选项
  • cafilecapath 参数用于指定一组被HTTPS请求信任的CA证书
  • cadefault 参数被忽略

三、urllib的高级使用

1. 使用代理

对于某些网站,若同一IP短时间内发送大量请求则可能会将该IP判定为爬虫,进而对该IP进行封禁,这样我们的爬虫就失效了,所以我们有必要使用随机的IP地址来绕开这一层检查,这里提供几个提供免费IP地址的网站(但是必须要明确的一点是免费的代理IP十分不稳定):

注意,这些IP都是会随时更新的,所以最好自己写一个爬虫去维护,这点我们将会在以后讲到

>>> import urllib.request
>>> import random
>>> ip_list = [
    {'http':'61.135.217.7:80'},
    {'http':'182.88.161.204:8123'}
]
>>> proxy_handler = urllib.request.ProxyHandler(random.choice(ip_list))
>>> opener = urllib.request.build_opener(proxy_handler)
>>> response = opener.open('http://www.httpbin.org/ip')
>>> print(response.read().decode('utf-8'))
{
  "origin": "61.135.217.7"
}

2. 使用Cookie

(1)获取Cookie

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


BAIDUID=486AED46E7F22C0A7A16D9FE6E627846:FG=1
BDRCVFR[RbWYmTxDkZm]=mk3SLVN4HKm
BIDUPSID=486AED46E7F22C0A7A16D9FE6E627846
H_PS_PSSID=1464_21106_26920
PSTM=1533990197
BDSVRTM=0
BD_HOME=0
delPer=0

(2)使用Cookie

>>> import urllib.request
>>> import http.cookiejar

#将cookie保存到文件方便以后使用
>>> cookie = http.cookiejar.MozillaCookieJar('cookie.txt')     
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> cookie.save(ignore_discard=True,ignore_expires=True)
#此时在程序同目录下已经生成了'cookie.txt'文件

#从文件读取cookie并附加到请求中
>>> cookie = http.cookiejar.MozillaCookieJar()
>>> cookie = cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True)
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
#此时已经得到了带有cookie请求返回的响应

写在后面的话 :经过上面的学习,我们已经初步了解了urllib使用的基本方法,下一篇文章我们将会使用urllib进行简单的实战训练,爬取有道翻译,实现一个翻译小程序,谢谢大家

阅读更多

没有更多推荐了,返回首页