Python爬虫之urllib库和requests库的基本使用

Python爬虫之基本库urllib的使用

在Python3中,有urllib库来实现请求的发送(将Python2中的urllib2已经统一至urllib库中)。

对于urllib库的疑问可以参照官网说明了解:https://docs.python.org/3/library/urllib.html

urllib库

urllib库是python内置的HTTP请求库,包含四个模块:

  • request:最基本的HTTP请求模块,可以用来模拟发送请求。
  • error:异常处理模块,如果出现请求错误,可以对这些异常进行捕获,防止程序意外终止。
  • parse:一个工具模块,提供了许多URL的处理方法,如拆分、合并等。
  • robotparser:主要用来识别网站的robot.txt文件。

发送请求

urlopen()

urllib.request的模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程。

首先给出urlopen()方法的API:urllib.request.urlopen(url, data=None, [timeout, ]***, cafile=None, capath=None, cadefault=False, context=None),后面会详细介绍各项参数意义。

下面我们简单的调用下urlopen()方法:

import urllib.request

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

可以得到如下输出:

<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->
<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">                 <![endif]-->
<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr">  <!--<![endif]-->

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
....#省略
</body>
</html>

接下来,我们看看urllib.request.urlopen()方法返回的是个是什么

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(type(response)) #打印response的类型

输出如下:

<class 'http.client.HTTPResponse'>

可以发现,返回的是一个HTTPResponse类型的对象。HTTPResponse类型的对象包含read()、readinto()、hetheader(name)、fileno()等方法和status等属性。如下打印了HTTPResponse类型的方法返回及其status属性。

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(response.status)
print(response.getheaders())

输出了状态码和相应的头信息,如下:

200
[('Connection', 'close'), ('Content-Length', '48730'), ('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'DENY'), ('Via', '1.1 vegur'), ('Via', '1.1 varnish'), ('Accept-Ranges', 'bytes'), ('Date', 'Mon, 27 Jul 2020 07:55:36 GMT'), ('Via', '1.1 varnish'), ('Age', '2423'), ('X-Served-By', 'cache-bwi5134-BWI, cache-hkg17928-HKG'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '30, 2173'), ('X-Timer', 'S1595836536.216510,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]

输出状态码200代表访问成功,常见的状态码还有404(页面未找到)400(服务器无法解析请求)、**500(服务器遇到错误)**等。

urlopen()——data参数

data参数是可选的,若添加此参数,需要使用bytes()方法将参数转化为bytes类型。并且请求方式将变为POST。

为将其转化为bytes类型,我们可以用bytes()方法,同时利用urllib.parse模块里的urlencode()方法将参数字典转化为字符串作为第一个参数;第二个参数是指定编码格式。

import urllib.request
import urllib.parse
mydict  = {
   'name':'Small_Fish'} 
mydata = bytes(urllib.parse.urlencode(mydict),encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post',data=mydata)#该链接可以用来测试POST请求
print(response.status)
print(response.read())

输出如下:

200
b'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "name": "Small_Fish"\n  }, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Content-Length": "15", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "httpbin.org", \n    "User-Agent": "Python-urllib/3.7", \n    "X-Amzn-Trace-Id": "Root=1-5f1e8dbc-6aa88726e6a39100e23797ed"\n  }, \n  "json": null, \n  "origin": "117.136.19.0", \n  "url": "http://httpbin.org/post"\n}\n'

可见返回的内容的"form"即为我们传递的参数,表面了是模拟表单的提交方式,以POST方式传输数据。

urlopen()——timeout参数

timeout参数根据字面意义大家应该就能猜到其意义了,该参数用于设置超时时间(单位:s),当发出的请求超出了该时间依然没有得到相应时,就会抛出异常,我们可以用try-except来捕获异常。

import urllib.request
import urllib.parse
import urllib.error
import socket

if __name__ =="__main__":
   mydata = bytes(urllib.parse.urlencode({'name':'Small_Fish'}),encoding='utf8')
   try:
      response = urllib.request.urlopen('http://httpbin.org/post',data = mydata,timeout = 0.1)#设置超时时间为0.1s,当超过改时间没有得到相应将抛出异常
   except urllib.error.URLError as e:
      if isinstance(e.reason,socket.timeout):#判断,如果异常原因是socket.timeout则打印TIME OUT
         print('TIME OUT')

输出如下:

TIME OUT

Request()

当请求中需要加入Headers等信息时,我们就需要用到更强大的Request类来构建请求。

API:class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

下面直接来说参数吧:

  • url:请求的URL
  • data:同urlopen中的data,为bytes类型。如果是字典需要先用urllib.parse.urlencode()进行编码
  • headers:请求头,是一个字典
  • origin_req_host:请求方的host名称或IP地址
  • unverifiable:表示请求是否是无法验证的,默认False。
  • method:请求的方法(GET、POST、PUT等)

还是举一个实例:

import urllib.request
import urllib.parse

if __name__ == '__main__':
   url = 'http://httpbin.org/post'  #参数URL
   headers = {
      'User-Agent': 'Mozilla/4.0(compatible; MISE 5.5;Windows NT)',
      'Host':'httpbin.org'}#参数Headers
   dict ={
      'name':'Small_Fish'} #参数data
   mydata = bytes(urllib.parse.urlencode(dict),encoding='utf-8')
   request =urllib.request.Request(url,data = mydata,headers = headers, method = 'POST')
   response = urllib.request.urlopen(request)#依然使用了urlopen()
   print(response.read().decode('utf8'))

输出如下:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "Small_Fish"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Content-Length": "8", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/4.0(compatible; MISE 5.5;Windows NT)", 
    "X-Amzn-Trace-Id": "Root=1-5f1e9458-03e22590f337243009a04b88"
  }, 
  "json": null, 
  "origin": "117.136.19.0", 
  "url": "http://httpbin.org/post"
}

观察发现我们成功设置了相应的data、headers、method,其中我们构造headers的"User-Agent"为"Mozilla/4.0(compatible; MISE 5.5;Windows NT)"是用来伪装成火狐浏览器。

同时,我们也发现我们依然用了urlopen(),只不过这次的参数不再是url,而是一个request类型的对象。

处理异常

URLError

URLError类来自urllib库的error模块,它继承自OSError类,是Error异常模块类的基类,由request模块产生的异常可以通过捕获这个类来处理。

from urllib import request, parse, error
import urllib

mydict  = {
   'name':'Small_Fish'}
mydata = bytes(urllib.parse.urlencode(mydict),encoding='utf8')
try:
   response = urllib.request.urlopen('http://sbsbsbsbsb.com',data=mydata,timeout=0.1)
   print(response.status)
   print(response.read())
except error.URLError as e:
   print(e.reason)

输出:

timed out

可以看到程序没有直接报错,而是打印出了异常信息,通过这样我们可以有效避免程序异常终止。

HTTPError

HTTPError异常类是URLError类的子类,专门用来处理HTTP请求错误。

HTTPError有三个属性:

  • code:返回HTTP的状态码
  • reason:返回错误的原因
  • headers:返回请求头
from urllib import request, parse, error
import urllib

try:
   response = urllib.request.urlopen('https://a.com')
   print(response.status)
except error.HTTPError as e:
   print(e.reason,e.code,e.Headers,sep='\n')

解析链接

urlparse()

API:urllib.parse.urlparse(urlstring,scheme=' ',allow_fragment=True)

该方法可以实现URL的识别和分段。

from urllib.parse import urlparse

res = urlparse('http://www.baidu.com/index/html;user?id=5#comment')
print(type(res),res,sep='\n')

输出如下:

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

返回的结果为ParseResult类型的一个对象,包含了6个部分scheme, netloc, path, params, query和 fragment

  • scheme:协议(http、https)
  • netloc:域名,第一个/符合前便是netloc
  • path::访问路径
  • params:参数, ;号后面便是params
  • query:查询条件,?后是查询条件
  • fragment:锚点,用于直接定位页面内部的下拉位置

因此我们得到了一个标准的链接格式:scheme://netloc/path;params?query#fragment

urlunparse()

urlunparse()构造一个URL,接受的参数是一个可迭代对象,但必须长度为6.

from urllib.parse import urlunparse


data = ['http','www.baidu.com','index.html','user','id=6','comment']
res = urlunparse(data)
print(type(res),res,sep='\n')

输出如下:

<class 'str'>
http://www.baidu.com/index.html;user?id=6#comment

返回的结果为str类型的一个对象,并且成功构造了相应的URL。

urlsplit()

urlsplit()与urlparse()非常相似,只不过不在单独解析params,只返回5个结果。

from urllib.parse import urlsplit

res = urlsplit('http://www.baidu.com/index/html;user?id=5#comment')
print(type(res),res,sep='\n')

输出如下:

<class 'urllib.parse.SplitResult'>
SplitResult(scheme='http', netloc='www.baidu.com', path='/index/html;user', query='id=5', fragment='comment')

由结果可知uesr被加入path中了。

urlunsplit()

urlunsplit()构造一个URL,接受的参数是一个可迭代对象,但必须长度为,类似urlunparse()就不再放代码了。

urljoin()

urljoin()就是用一个链接(参数1)对另外一个新链接(参数2)缺失部分进行补充,最后返回结果。

from urllib.parse import urljoin

res = urljoin('http://www.baidu.com/index.php?id=5#comment','//www.tianmao.com')
print(res)

输出:

http://www.tianmao.com

urlencode()

urlencode()常常用于构造GET请求参数。

from urllib.parse import urlencode

dicts = {
   'name':'Small_Fish',
   'years':21}
base_url = 'http://www.baidu.com/'
url = base_url + urlencode(dicts)

print(url)

输出:

http://www.baidu.com/name=Small_Fish&years=21

这个方法非常常用。有时为了更加方便地构造参数,我们会事先用字典来表示。要转化为URL参数时,只需要调用方法就行。

quote()和unquote()

quote()该方法可以将内容转化为URL编码的格式。因为URL中带有中文参数时,可能会导致乱码的问题,利用此方法可以将中文转化为URL编码。

相应的unquote()可以对URL编码进行解码。

from urllib.parse import urlencode,quote,unquote

name = '帅哥'
base_url = 'http://www.baidu.com/'
print(base_url+name)
url = base_url +quote(name)

print(url)
print(unquote(url))

输出如下:

http://www.baidu.com/帅哥
http://www.baidu.com/%E5%B8%85%E5%93%A5
http://www.baidu.com/帅哥

如上便实现了编码和解码的过程。

Python爬虫之requests库的使用

requests库是在python3爬虫中相对于urllib库更强大的一个库,有了它我们可以轻松进行Cookies、登录验证、代理设置等操作。

requests库的安装

windows下在命令行窗口下输入pip3 install requests命令即可完成安装,非常简单。

requests的GET请求

HTTP中最常见的就是GET请求,下面介绍一下利用requests构建GET请求的方法。

requests.get()

requests中以GET方式请求网页的方法就是get,是不是非常直观呢?(相对于urllib库)

如↓:

import requests

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

输出如下:

<class 'requests.models.Response'>
200
<!DOCTYPE html>

<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.c
....#省略OTZ
src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

可见requests.get()返回的是一个Response类型的对象,同时也可以调用其状态码、内容等属性了解相应结果。

如果我们想向请求中添加参数,通过get()方法也可以很轻松实现:

import requests

param = {
   'name':'Small_Fish',
   'years':21
   }

headers ={
   'User-Agent':'Mozilla/5.0',
   }
response = requests.get('http://httpbin.org/get',params = param,headers=headers)
print(type(response))
print(response.status_code)
print(response.text)

输出如下:

<class 'requests.models.Response'>
200
{
  "args": {
    "name": "Small_Fish", 
    "years": "21"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/5.0", 
    "X-Amzn-Trace-Id": "Root=1-5f1fcc0b-b1818391d5a51ffc4dd76471"
  }, 
  "origin": "117.136.19.0", 
  "url": "http://httpbin.org/get?name=Small_Fish&years=21"
}

requests的POST请求

另外一种比较常见的请求方式是POST请求,使用方法也非常简单。

import requests

param = {
   'name':'Small_Fish',
   'years':'21'
   }
response = requests.post('http://httpbin.org/post',data = param)
print(response.text)


输出如下:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "Small_Fish", 
    "years": "21"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "24", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.24.0", 
    "X-Amzn-Trace-Id": "Root=1-5f1fcdba-bd70c740c324e9401d5cf270"
  }, 
  "json": null, 
  "origin": "117.136.19.0", 
  "url": "http://httpbin.org/post"
}

猜你喜欢

转载自blog.csdn.net/qq_42642142/article/details/107619440