1. 程式人生 > >概述和HTTP請求 和 響應處理

概述和HTTP請求 和 響應處理

1、概述

  爬蟲,應該稱為網路爬蟲,也叫網頁蜘蛛人,網路螞蟻等

  搜尋引擎,就是網路爬蟲的應用者

2、爬蟲分類

  通用爬蟲:

    常見就是搜尋引擎,無差別的收集資料,儲存,提交關鍵字,構建索引庫,給使用者提供搜尋介面

    爬取一般流程:

      1、初始一批URL,將這些URL放到待爬的佇列

      2、從佇列取出這些URL,通過DNS 解析IP ,對IP 對應的站點下載HTML頁面,儲存到本地伺服器中,爬取完URL放到已經爬取的佇列中

      3、分析這些網頁內筒,找出網頁裡面的其他關心的URL連線,繼續執行第二步,直到爬取條件結束。

    搜尋引擎如何獲取一個新網站的URL

      • 新網站主動提交給搜尋引擎
      • 通過其他網站頁面的外連線
      • 搜尋引擎和DNS 服務商合作,獲取最新收錄的網站。

  聚焦爬蟲:

    有針對的編寫特定領域資料的爬蟲程式,針對某些 類別的資料採集的爬蟲,是面向主體的爬蟲

3、Robots 協議:

  指定一個robots.txt 檔案,告訴爬蟲引擎什麼可以爬,什麼不可以爬

  /  表示網站根目錄, 表示網站的所有目錄

  Allow:允許, Disallow:不允許

  可以使用萬用字元

  例如:淘寶:http://www.taobao.com/robots.txt

    

View Code

 

  這是一個君子協定,爬亦有道

  這個協議為了讓搜尋引擎更有效率的搜尋自己內容,提供瞭如Sitemap 這樣的檔案

  Sitemap 往往死一個XML 檔案,提供了網站想讓大家爬取的內容的更新資訊

  這個檔案禁止爬取的往往又是我們可能感興趣的內容,它反而洩露了這些地址。

4、HTTP請求和響應的處理

  其實爬取網頁就是通過HTTP 協議訪問網頁, 不過通過瀏覽器訪問往往是認為行為,把這種行為變成程式來訪問。

  urllib包:

    urllib 是標準庫,它一個工具包模組,包含下面的模組處理 url

      • urllib.request 用於開啟和讀寫url
      • urllib.error 包含了有urllib.request引起的異常。
      • urllib.parse 用於解析url
      • urllib.robotparser 分析robots.txt 檔案

    Python2 中提供了urlib 和urllib2 ,前者 提供了較為底層的介面,urllib2 對urllib 進行了進一步的封裝,P櫻桃紅3中將urllib合併到餓了urllib中,並更名為標準庫urllib包

  urllib.request模組

    模組定義了在基本和摘要式身份驗證,重定向,cookies等應用中開啟url(主要是HTTP)的函式和類

    urlopen方法:

      urlopen(url,data=None)

      url 是連結地址字串,或請求類的例項

      data提交的資料,如果data為None,發起的是GET請求,否則發起POST請求,

      見 urllib.request.Requset.get_method返回 http.client.HTTPResponse類的響應物件,這是一個類檔案物件    

 1 from urllib.request import urlopen
 2 from urllib import request
 3 
 4 
 5 # 開啟一個url返回一個響應物件,類檔案物件
 6 # 下面的連結,會301 跳轉
 7 response = urlopen('https://www.bing.com') #GET 方法
 8 print(response)-----類檔案物件
 9 with response:
10     print(1, type(response))
11     print(2, response.status, response.reason)
12     print(3, response.geturl) 13 print(4, response.info()) 14 print(5, response.read()) 15 16 print(response.closed)

 

列印結果

    上面,通過urllib.requset.urlopen 方法,發起一個HTTP的GET請求,web 伺服器返回了網頁內容,響應的資料被封裝到類檔案物件中,可以通過read方法,readline方法,readlines方法,獲取資料,status,和reason   表示狀態碼, info方法表示返回header資訊等

 

  User-Agent問題

    上例的程式碼非常精簡,即可以獲得網站的響應資料,但是目前urlopen方法通過url 字串和data發起HTTP請求

    如果想修改HTTP頭,例如:useragent 就得藉助其他方式

    原碼中構造的useragent 如下:    

 1 class OpenerDirector:
 2     def __init__(self):
 3         client_version = "Python-urllib/%s" % __version__
 4         self.addheaders = [('User-agent', client_version)]
 5         # self.handlers is retained only for backward compatibility
 6         self.handlers = []
 7         # manage the individual handlers
 8         self.handle_open = {}
 9         self.handle_error = {}
10         self.process_response = {} 11 self.process_request = {}

 

    當前顯示為 Python-urllib/3.7

    有些網站是反爬蟲的,所以要把爬蟲偽裝成瀏覽器,隨便開啟一個瀏覽器,複製瀏覽器的UA(useragent) 值,用來偽裝。

  Request類

    Request(url, data=None, headers={} )

    初始化方法,構造一個請求物件,可新增一個header的字典

    data 引數決定是GET 還是POST 請求(data 為None是GET,有資料,就是POST)

    add_header(key, val) 為header總增加一個鍵值對。    

 1 from urllib.request import Request, urlopen
 2 
 3 # 開啟一個url 返回一個Requset 請求物件
 4 # url = 'http://movie.douban.com/' 注意尾部的斜杆一定要有
 5 url = 'http://www.bing.com/'
 6 
 7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 8 
 9 # 構造一個請求物件
10 request = Request(url)
11 request.add_header('User-Agent',ua)
12 
13 print(type(request),'=============')
14 print(5,request.get_header('User-Agent'))
15 # 構建響應物件
16 response = urlopen(request, timeout=20) # requset物件或者url 都可以
17 
18 print(type(response)) 19 20 21 with response: 22 # getcode本質上返回的就是 status 23 print(1, response.status, response.getcode(),response.reason) 24 # 返回資料的url,如果重定向,這個url和原始url不一樣 25 print(2, response.geturl()) 26 # 返回響應頭資訊 27 print(3, response.info()) 28 # 讀取返回的內容 29 print(4, response.read()) 30 31 print(5,request.get_header('User-Agent')) 32 print(6,'user-agent'.capitalize())

 

列印結果

 

   urllib.parse 模組

   該模組可以完成對url的編解碼

     編碼:urlencode函式第一個引數要求是一個字典或者二元組序列

1 from urllib import parse
2 
3 u = parse.urlencode({
4     'url':'http://www.magedu.com/python',
5     'p_url':'http:www.magedu.com/python?id=1&name=張三'
6 })
7 print(u)

 

 

url=http%3A%2F%2Fwww.magedu.com%2Fpython&p_url=http%3Awww.magedu.com%2Fpython%3Fid%3D1%26name%3D%E5%BC%A0%E4%B8%89

 

   從執行結果來看冒號。斜杆 & 等號,問號都被編碼,%之後實際上是單位元組十六進位制表示的值

  一般來說,url中的地址部分,一般不需要使用中文路徑,但是引數部分,不管 GET 還是post 方法,提交的資料中,可能有斜杆等符號,這樣的字元表示資料,不表示元字元,如果直接傳送給伺服器端,就會導致接收方無法判斷誰是元字元,誰是資料,為了安全,一般會將資料部分的字串做url 編碼,這樣就不會有歧義了

,後來可以傳送中文,同樣會做編碼,一般先按照字符集的encoding要求轉化成位元組序列,每一個位元組對應的十六進位制字串前加上百分號即可。

 1 '''
 2 網頁使用utf-8 編碼
 3 https://www.baidu.com/s?wd=中
 4 上面的url編碼後,如下:
 5 https://www.baidu.com/s?wd=%E4%B8%AD
 6 '''
 7 from urllib import parse
 8 
 9 u = parse.urlencode({'wd':'中'}) # 編碼
10 print(u)
11 
12 url = 'https://www.baidu.com/s?{}'.format(u)
13 print(url)
14 
15 print('中'.encode('utf-8'))
16 # 解碼
17 print(parse.unquote(u)) 18 print(parse.unquote(url))

 

   列印結果:

1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt21.py
2 wd=%E4%B8%AD
3 https://www.baidu.com/s?wd=%E4%B8%AD
4 b'\xe4\xb8\xad'
5 wd=中
6 https://www.baidu.com/s?wd=中
7 
8 Process finished with exit code 0

 

5、提交方法method

  最常用的HTTP互動 資料的方法是GET ,POST

  GET 方法,資料是通過URL 傳遞的,也就是說資料時候在http 報文的header部分

  POST方法,資料是放在http報文的body 部分提交的

  資料都是鍵值對形式,多個引數之間使用&符號連結,

   GET方法:

  連線 bing 搜尋引擎官網,獲取一個搜尋的URL: http://cn.bing.com/search?q=張三

  需求:

  請寫程式需完成對關鍵字的bing 搜尋, 將返回的結果儲存到一個網頁檔案中。  

 1 from urllib.request import Request, urlopen
 2 from urllib.parse import urlencode
 3 
 4 keyword = input('>>輸入關鍵字')
 5 
 6 data = urlencode({'q':keyword})
 7 
 8 base_url = 'http://cn.bing.com/search'
 9 
10 url = '{}?{}'.format(base_url, data)
11 
12 print(url) 13 14 # 偽裝 15 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36' 16 request = Request(url, headers={'User-agent':ua}) 17 response = urlopen(request) 18 19 with response: 20 with open('./bing.html', 'wb') as f: 21 f.write(response.read())

 

   結果:

   http GET 獲取的文字 是位元組形式(二進位制)

   POST 方法:

     http://httpbin.org/ 測試網站  像一個echo,你發什麼,給你什麼

 1 from urllib.request import Request, urlopen
 2 from urllib.parse import urlencode
 3 import simplejson
 4 
 5 request = Request('http://httpbin.org/post')
 6 
 7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 8 
 9 request.add_header('User-agent', ua)
10 
11 data = urlencode({'name':'張三,@=/&=', 'age':'12'}) 12 13 print(data) 14 15 res = urlopen(request, data=data.encode())# POST f方法 Form提交資料 16 with res: 17 print(res.read().decode())

 

   結果:

 1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt23.py
 2 name=%E5%BC%A0%E4%B8%89%2C%40%3D%2F%26%3D&age=12
 3 {
 4   "args": {}, 
 5   "data": "", 
 6   "files": {}, 
 7   "form": { 8 "age": "12", 9 "name": "\u5f20\u4e09,@=/&=" 10  }, 11 "headers": { 12 "Accept-Encoding": "identity", 13 "Connection": "close", 14 "Content-Length": "48", 15 "Content-Type": "application/x-www-form-urlencoded", 16 "Host": "httpbin.org", 17 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36" 18  }, 19 "json": null, 20 "origin": "61.149.196.193", 21 "url": "http://httpbin.org/post" 22 } 23 24 25 Process finished with exit code 0

 

     

  處理JSON資料 

     檢視豆瓣電影,看到最近熱門電影的熱門

    

     通過分析,我們知道這部分內容,是通過AJAX 從後臺拿到的json資料

      

    訪問ur 是:https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0

      

       伺服器返回的資料如上

      

1 from urllib import parse
2 將url解碼:
3 print(parse.unquote('https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0'))
4 
5 ----------------------------------------------------------------------------------
6 https://movie.douban.com/j/search_subjects?type=movie&tag=熱門&page_limit=50&page_start=0

 

     通過程式碼獲取上述截圖內容:

  

 6、HTTPS 證書忽略

  HTTPS使用SSL 安全套接層協議,在傳輸層對網路資料進行加密,HTTPS 使用的時候,需要證書,而證書需要cA認證 

 1 from urllib.request import Request, urlopen
 2 
 3 # 可以訪問
 4 # request = Request('http://www.12306.cn/mormhweb')
 5 # request = Request('https://www.baidu.com')
 6 
 7 request = Request('https://www.12306.cn/mormhweb/')
 8 
 9 
10 print(request)
11 
12 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
13 
14 request.add_header('User-agent', ua)
15 
16 with urlopen(request) as res:
17     print(res._method) 18 print(res.read())

 

    

  

  忽略證書不安全資訊:  

 1 from urllib.request import Request, urlopen
 2 import ssl
 3 
 4 # 可以訪問
 5 # request = Request('http://www.12306.cn/mormhweb')
 6 # request = Request('https://www.baidu.com')
 7 
 8 request = Request('https://www.12306.cn/mormhweb/')
 9 
10 
11 print(request)
12 
13 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
14 
15 request.add_header('User-agent', ua)
16 # 忽略不信任的證書(不用校驗的上下文) 17 context = ssl._create_unverified_context() 18 res = urlopen(request, context=context) 19 
20 
21 with res: 22 print(res._method) 23 print(res.geturl()) 24 print(res.read().decode())

 

  

7、urllib3 庫

  https:// urllib3.readthedocs.io/en/latest

  標準庫urllib缺少了一些關鍵的功能,非標準庫的第三方庫 urlib3 提供了,比如說連線池管理

  安裝:pip install urllib3  

 1 import urllib3
 2 
 3 url = 'http://movie.douban.com/'
 4 
 5 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 6 
 7 # 連線池管理
 8 with urllib3.PoolManager() as http:
 9     response = http.request('GET', url, headers={"User-agent":ua})
10     print(1,type(response))
11     print(2,response.status, response.reason)
12     print(3,response.headers) 13 print(4,response.data.decode())

 

   結果:

View Code

 

 

8、requests庫(開發真正用的庫)

  requests 使用了 urllib3, 但是 API 更加友好,推薦使用

 1 import requests
 2 
 3 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 4 
 5 url = 'http://movie.douban.com/'
 6 
 7 response = requests.request('GET', url,headers={'User-agent':ua})
 8 
 9 with response:
10     print(type(response))
11     print(response)
12     print(response.url) 13 print((response.status_code)) 14 print(response.request.headers) #請求頭 15 print(response.headers) # 響應頭 16 print(response.encoding) 17 response.encoding = 'utf-8' 18 print(response.text[:100]) 19 20 with open('./movie.html', 'w', encoding='utf-8') as f: 21 f.write(response.text) # 儲存檔案

  結果:

 1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt25.py
 2 <class 'requests.models.Response'>
 3 <Response [200]>
 4 https://movie.douban.com/
 5 200
 6 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
 7 {'Date': 'Wed, 05 Dec 2018 03:34:12 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=30', 'Vary': 'Accept-Encoding', 'X-Xss-Protection': '1; mode=block', 'X-Douban-Mobileapp': '0', 'Expires': 'Sun, 1 Jan 2006 01:00:00 GMT', 'Pragma': 'no-cache', 'Cache-Control': 'must-revalidate, no-cache, private', 'Set-Cookie': 'll="108288"; path=/; domain=.douban.com; expires=Thu, 05-Dec-2019 03:34:12 GMT, bid=8QfNwA452hU; Expires=Thu, 05-Dec-19 03:34:12 GMT; Domain=.douban.com; Path=/', 'X-DOUBAN-NEWBID': '8QfNwA452hU', 'X-DAE-Node': 'brand15', 'X-DAE-App': 'movie', 'Server': 'dae', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip'}
 8 utf-8
 9 <!DOCTYPE html>
10 <html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
11 <head>
12     <meta http-equiv="
13 
14 Process finished with exit code 0

 

 

  request預設使用Session 物件,是為了在多次 和伺服器互動中保留 會話的資訊,例如cookie

  否則,每次都要重新發起請求

  

 1 # 直接使用Session
 2 import requests
 3 
 4 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 5 
 6 urls = ['https://www.baidu.com','https://www.baidu.com']
 7 
 8 session = requests.Session()
 9 with session:
10     for url in urls:
11         # response = session.get(url, headers={'User-agent':ua})
12         response = requests.request('GET', url, headers={'User-agent':ua}) # 相當於每次都是新的請求,也就是開啟了兩個瀏覽器而已
13         print(response) 14  with response: 15 print(response.request.headers) 16 print(response.cookies) 17 print(response.text[:20]) 18 print('----------------------------------------------') 19 ''' 20 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt19.py 21 <Response [200]> 22 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 23 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC144A1F6BEA823FF4F5:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC144A1F6BEA823FF4F5 for .baidu.com/>, <Cookie H_PS_PSSID=1444_21081_27509 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 24 <!DOCTYPE html> 25 <!-- 26 ---------------------------------------------- 27 <Response [200]> 28 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 29 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC14FA9EECCB0280B074:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC14FA9EECCB0280B074 for .baidu.com/>, <Cookie H_PS_PSSID=26523_1469_25810_21098_26350_22073 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 30 <!DOCTYPE html> 31 <!-- 32 ---------------------------------------------- 33 34 Process finished with exit code 0 35 36 ''' 37 38 with session: 39 for url in urls: 40 response = session.get(url, headers={'User-agent':ua}) 41 # response = requests.request('GET', url, headers={'User-agent':ua}) 42 print(response) 43  with response: 44 print(response.request.headers) 45 print(response.cookies) 46 print(response.text[:20]) 47 print('----------------------------------------------') 48 ''' 49 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt19.py 50 <Response [200]> 51 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 52 <RequestsCookieJar[<Cookie BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1 for .baidu.com/>, <Cookie BIDUPSID=5A320955507582B839E723DB6F55B2BD for .baidu.com/>, <Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie PSTM=1543981366 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 53 <!DOCTYPE html> 54 <!-- 55 ---------------------------------------------- 56 <Response [200]> 第二次訪問,帶上了cookie 57 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1; BIDUPSID=5A320955507582B839E723DB6F55B2BD; H_PS_PSSID=1434_21091_18559_27245_27509; PSTM=1543981366; delPer=0; BDSVRTM=0; BD_HOME=0'} 58 <RequestsCookieJar[<Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 59 <!DOCTYPE html> 60 <!-- 61 ---------------------------------------------- 62 63 Process finished with exit code 0 64 65 '''

 

 

 

 

 

 

 

 

 

 

1、概述

  爬蟲,應該稱為網路爬蟲,也叫網頁蜘蛛人,網路螞蟻等

  搜尋引擎,就是網路爬蟲的應用者

2、爬蟲分類

  通用爬蟲:

    常見就是搜尋引擎,無差別的收集資料,儲存,提交關鍵字,構建索引庫,給使用者提供搜尋介面

    爬取一般流程:

      1、初始一批URL,將這些URL放到待爬的佇列

      2、從佇列取出這些URL,通過DNS 解析IP ,對IP 對應的站點下載HTML頁面,儲存到本地伺服器中,爬取完URL放到已經爬取的佇列中

      3、分析這些網頁內筒,找出網頁裡面的其他關心的URL連線,繼續執行第二步,直到爬取條件結束。

    搜尋引擎如何獲取一個新網站的URL

      • 新網站主動提交給搜尋引擎
      • 通過其他網站頁面的外連線
      • 搜尋引擎和DNS 服務商合作,獲取最新收錄的網站。

  聚焦爬蟲:

    有針對的編寫特定領域資料的爬蟲程式,針對某些 類別的資料採集的爬蟲,是面向主體的爬蟲

3、Robots 協議:

  指定一個robots.txt 檔案,告訴爬蟲引擎什麼可以爬,什麼不可以爬

  /  表示網站根目錄, 表示網站的所有目錄

  Allow:允許, Disallow:不允許

  可以使用萬用字元

  例如:淘寶:http://www.taobao.com/robots.txt    

View Code

 

  這是一個君子協定,爬亦有道

  這個協議為了讓搜尋引擎更有效率的搜尋自己內容,提供瞭如Sitemap 這樣的檔案

  Sitemap 往往死一個XML 檔案,提供了網站想讓大家爬取的內容的更新資訊

  這個檔案禁止爬取的往往又是我們可能感興趣的內容,它反而洩露了這些地址。

4、HTTP請求和響應的處理

  其實爬取網頁就是通過HTTP 協議訪問網頁, 不過通過瀏覽器訪問往往是認為行為,把這種行為變成程式來訪問。

  urllib包:

    urllib 是標準庫,它一個工具包模組,包含下面的模組處理 url

      • urllib.request 用於開啟和讀寫url
      • urllib.error 包含了有urllib.request引起的異常。
      • urllib.parse 用於解析url
      • urllib.robotparser 分析robots.txt 檔案

    Python2 中提供了urlib 和urllib2 ,前者 提供了較為底層的介面,urllib2 對urllib 進行了進一步的封裝,P櫻桃紅3中將urllib合併到餓了urllib中,並更名為標準庫urllib包

  urllib.request模組

    模組定義了在基本和摘要式身份驗證,重定向,cookies等應用中開啟url(主要是HTTP)的函式和類

    urlopen方法:

      urlopen(url,data=None)

      url 是連結地址字串,或請求類的例項

      data提交的資料,如果data為None,發起的是GET請求,否則發起POST請求,

      見 urllib.request.Requset.get_method返回 http.client.HTTPResponse類的響應物件,這是一個類檔案物件    

 1 from urllib.request import urlopen
 2 from urllib import request
 3 
 4 
 5 # 開啟一個url返回一個響應物件,類檔案物件
 6 # 下面的連結,會301 跳轉
 7 response = urlopen('https://www.bing.com') #GET 方法
 8 print(response)-----類檔案物件
 9 with response:
10     print(1, type(response))
11     print(2, response.status, response.reason)
12     print(3, response.geturl) 13 print(4, response.info()) 14 print(5, response.read()) 15 16 print(response.closed)

 

列印結果

    上面,通過urllib.requset.urlopen 方法,發起一個HTTP的GET請求,web 伺服器返回了網頁內容,響應的資料被封裝到類檔案物件中,可以通過read方法,readline方法,readlines方法,獲取資料,status,和reason   表示狀態碼, info方法表示返回header資訊等

 

  User-Agent問題

    上例的程式碼非常精簡,即可以獲得網站的響應資料,但是目前urlopen方法通過url 字串和data發起HTTP請求

    如果想修改HTTP頭,例如:useragent 就得藉助其他方式

    原碼中構造的useragent 如下:    

 1 class OpenerDirector:
 2     def __init__(self):
 3         client_version = "Python-urllib/%s" % __version__
 4         self.addheaders = [('User-agent', client_version)]
 5         # self.handlers is retained only for backward compatibility
 6         self.handlers = []
 7         # manage the individual handlers
 8         self.handle_open = {}
 9         self.handle_error = {}
10         self.process_response = {} 11 self.process_request = {}

 

    當前顯示為 Python-urllib/3.7

    有些網站是反爬蟲的,所以要把爬蟲偽裝成瀏覽器,隨便開啟一個瀏覽器,複製瀏覽器的UA(useragent) 值,用來偽裝。

  Request類

    Request(url, data=None, headers={} )

    初始化方法,構造一個請求物件,可新增一個header的字典

    data 引數決定是GET 還是POST 請求(data 為None是GET,有資料,就是POST)

    add_header(key, val) 為header總增加一個鍵值對。    

 1 from urllib.request import Request, urlopen
 2 
 3 # 開啟一個url 返回一個Requset 請求物件
 4 # url = 'http://movie.douban.com/' 注意尾部的斜杆一定要有
 5 url = 'http://www.bing.com/'
 6 
 7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 8 
 9 # 構造一個請求物件
10 request = Request(url)
11 request.add_header('User-Agent',ua)
12 
13 print(type(request),'=============')
14 print(5,request.get_header('User-Agent'))
15 # 構建響應物件
16 response = urlopen(request, timeout=20) # requset物件或者url 都可以
17 
18 print(type(response)) 19 20 21 with response: 22 # getcode本質上返回的就是 status 23 print(1, response.status, response.getcode(),response.reason) 24 # 返回資料的url,如果重定向,這個url和原始url不一樣 25 print(2, response.geturl()) 26 # 返回響應頭資訊 27 print(3, response.info()) 28 # 讀取返回的內容 29 print(4, response.read()) 30 31 print(5,request.get_header('User-Agent')) 32 print(6,'user-agent'.capitalize())

 

列印結果

 

   urllib.parse 模組

   該模組可以完成對url的編解碼

     編碼:urlencode函式第一個引數要求是一個字典或者二元組序列

1 from urllib import parse
2 
3 u = parse.urlencode({
4     'url':'http://www.magedu.com/python',
5     'p_url':'http:www.magedu.com/python?id=1&name=張三'
6 })
7 print(u)

 

 

url=http%3A%2F%2Fwww.magedu.com%2Fpython&p_url=http%3Awww.magedu.com%2Fpython%3Fid%3D1%26name%3D%E5%BC%A0%E4%B8%89

 

   從執行結果來看冒號。斜杆 & 等號,問號都被編碼,%之後實際上是單位元組十六進位制表示的值

  一般來說,url中的地址部分,一般不需要使用中文路徑,但是引數部分,不管 GET 還是post 方法,提交的資料中,可能有斜杆等符號,這樣的字元表示資料,不表示元字元,如果直接傳送給伺服器端,就會導致接收方無法判斷誰是元字元,誰是資料,為了安全,一般會將資料部分的字串做url 編碼,這樣就不會有歧義了

,後來可以傳送中文,同樣會做編碼,一般先按照字符集的encoding要求轉化成位元組序列,每一個位元組對應的十六進位制字串前加上百分號即可。

 1 '''
 2 網頁使用utf-8 編碼
 3 https://www.baidu.com/s?wd=中
 4 上面的url編碼後,如下:
 5 https://www.baidu.com/s?wd=%E4%B8%AD
 6 '''
 7 from urllib import parse
 8 
 9 u = parse.urlencode({'wd':'中'}) # 編碼
10 print(u)
11 
12 url = 'https://www.baidu.com/s?{}'.format(u)
13 print(url)
14 
15 print('中'.encode('utf-8'))
16 # 解碼
17 print(parse.unquote(u)) 18 print(parse.unquote(url))

 

   列印結果:

1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt21.py
2 wd=%E4%B8%AD
3 https://www.baidu.com/s?wd=%E4%B8%AD
4 b'\xe4\xb8\xad'
5 wd=中
6 https://www.baidu.com/s?wd=中
7 
8 Process finished with exit code 0

 

5、提交方法method

  最常用的HTTP互動 資料的方法是GET ,POST

  GET 方法,資料是通過URL 傳遞的,也就是說資料時候在http 報文的header部分

  POST方法,資料是放在http報文的body 部分提交的

  資料都是鍵值對形式,多個引數之間使用&符號連結,

   GET方法:

  連線 bing 搜尋引擎官網,獲取一個搜尋的URL: http://cn.bing.com/search?q=張三

  需求:

  請寫程式需完成對關鍵字的bing 搜尋, 將返回的結果儲存到一個網頁檔案中。  

 1 from urllib.request import Request, urlopen
 2 from urllib.parse import urlencode
 3 
 4 keyword = input('>>輸入關鍵字')
 5 
 6 data = urlencode({'q':keyword})
 7 
 8 base_url = 'http://cn.bing.com/search'
 9 
10 url = '{}?{}'.format(base_url, data)
11 
12 print(url) 13 14 # 偽裝 15 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36' 16 request = Request(url, headers={'User-agent':ua}) 17 response = urlopen(request) 18 19 with response: 20 with open('./bing.html', 'wb') as f: 21 f.write(response.read())

 

   結果:

   http GET 獲取的文字 是位元組形式(二進位制)

   POST 方法:

     http://httpbin.org/ 測試網站  像一個echo,你發什麼,給你什麼

 1 from urllib.request import Request, urlopen
 2 from urllib.parse import urlencode
 3 import simplejson
 4 
 5 request = Request('http://httpbin.org/post')
 6 
 7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 8 
 9 request.add_header('User-agent', ua)
10 
11 data = urlencode({'name':'張三,@=/&=', 'age':'12'}) 12 13 print(data) 14 15 res = urlopen(request, data=data.encode())# POST f方法 Form提交資料 16 with res: 17 print(res.read().decode())

 

   結果:

 1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt23.py
 2 name=%E5%BC%A0%E4%B8%89%2C%40%3D%2F%26%3D&age=12
 3 {
 4   "args": {}, 
 5   "data": "", 
 6   "files": {}, 
 7   "form": { 8 "age": "12", 9 "name": "\u5f20\u4e09,@=/&=" 10  }, 11 "headers": { 12 "Accept-Encoding": "identity", 13 "Connection": "close", 14 "Content-Length": "48", 15 "Content-Type": "application/x-www-form-urlencoded", 16 "Host": "httpbin.org", 17 "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36" 18  }, 19 "json": null, 20 "origin": "61.149.196.193", 21 "url": "http://httpbin.org/post" 22 } 23 24 25 Process finished with exit code 0

 

     

  處理JSON資料 

     檢視豆瓣電影,看到最近熱門電影的熱門

    

     通過分析,我們知道這部分內容,是通過AJAX 從後臺拿到的json資料

      

    訪問ur 是:https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0

      

       伺服器返回的資料如上

      

1 from urllib import parse
2 將url解碼:
3 print(parse.unquote('https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0'))
4 
5 ----------------------------------------------------------------------------------
6 https://movie.douban.com/j/search_subjects?type=movie&tag=熱門&page_limit=50&page_start=0

 

     通過程式碼獲取上述截圖內容:

  

 6、HTTPS 證書忽略

  HTTPS使用SSL 安全套接層協議,在傳輸層對網路資料進行加密,HTTPS 使用的時候,需要證書,而證書需要cA認證 

 1 from urllib.request import Request, urlopen
 2 
 3 # 可以訪問
 4 # request = Request('http://www.12306.cn/mormhweb')
 5 # request = Request('https://www.baidu.com')
 6 
 7 request = Request('https://www.12306.cn/mormhweb/')
 8 
 9 
10 print(request)
11 
12 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
13 
14 request.add_header('User-agent', ua)
15 
16 with urlopen(request) as res:
17     print(res._method) 18 print(res.read())

 

    

  

  忽略證書不安全資訊:  

 1 from urllib.request import Request, urlopen
 2 import ssl
 3 
 4 # 可以訪問
 5 # request = Request('http://www.12306.cn/mormhweb')
 6 # request = Request('https://www.baidu.com')
 7 
 8 request = Request('https://www.12306.cn/mormhweb/')
 9 
10 
11 print(request)
12 
13 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
14 
15 request.add_header('User-agent', ua)
16 # 忽略不信任的證書(不用校驗的上下文) 17 context = ssl._create_unverified_context() 18 res = urlopen(request, context=context) 19 
20 
21 with res: 22 print(res._method) 23 print(res.geturl()) 24 print(res.read().decode())

 

  

7、urllib3 庫

  https:// urllib3.readthedocs.io/en/latest

  標準庫urllib缺少了一些關鍵的功能,非標準庫的第三方庫 urlib3 提供了,比如說連線池管理

  安裝:pip install urllib3  

 1 import urllib3
 2 
 3 url = 'http://movie.douban.com/'
 4 
 5 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 6 
 7 # 連線池管理
 8 with urllib3.PoolManager() as http:
 9     response = http.request('GET', url, headers={"User-agent":ua})
10     print(1,type(response))
11     print(2,response.status, response.reason)
12     print(3,response.headers) 13 print(4,response.data.decode())

 

   結果:

View Code

 

 

8、requests庫(開發真正用的庫)

  requests 使用了 urllib3, 但是 API 更加友好,推薦使用

 1 import requests
 2 
 3 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 4 
 5 url = 'http://movie.douban.com/'
 6 
 7 response = requests.request('GET', url,headers={'User-agent':ua})
 8 
 9 with response:
10     print(type(response))
11     print(response)
12     print(response.url) 13 print((response.status_code)) 14 print(response.request.headers) #請求頭 15 print(response.headers) # 響應頭 16 print(response.encoding) 17 response.encoding = 'utf-8' 18 print(response.text[:100]) 19 20 with open('./movie.html', 'w', encoding='utf-8') as f: 21 f.write(response.text) # 儲存檔案

  結果:

 1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt25.py
 2 <class 'requests.models.Response'>
 3 <Response [200]>
 4 https://movie.douban.com/
 5 200
 6 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
 7 {'Date': 'Wed, 05 Dec 2018 03:34:12 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=30', 'Vary': 'Accept-Encoding', 'X-Xss-Protection': '1; mode=block', 'X-Douban-Mobileapp': '0', 'Expires': 'Sun, 1 Jan 2006 01:00:00 GMT', 'Pragma': 'no-cache', 'Cache-Control': 'must-revalidate, no-cache, private', 'Set-Cookie': 'll="108288"; path=/; domain=.douban.com; expires=Thu, 05-Dec-2019 03:34:12 GMT, bid=8QfNwA452hU; Expires=Thu, 05-Dec-19 03:34:12 GMT; Domain=.douban.com; Path=/', 'X-DOUBAN-NEWBID': '8QfNwA452hU', 'X-DAE-Node': 'brand15', 'X-DAE-App': 'movie', 'Server': 'dae', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip'}
 8 utf-8
 9 <!DOCTYPE html>
10 <html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
11 <head>
12     <meta http-equiv="
13 
14 Process finished with exit code 0

 

 

  request預設使用Session 物件,是為了在多次 和伺服器互動中保留 會話的資訊,例如cookie

  否則,每次都要重新發起請求

  

 1 # 直接使用Session
 2 import requests
 3 
 4 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
 5 
 6 urls = ['https://www.baidu.com','https://www.baidu.com']
 7 
 8 session = requests.Session()
 9 with session:
10     for url in urls:
11         # response = session.get(url, headers={'User-agent':ua})
12         response = requests.request('GET', url, headers={'User-agent':ua}) # 相當於每次都是新的請求,也就是開啟了兩個瀏覽器而已
13         print(response) 14  with response: 15 print(response.request.headers) 16 print(response.cookies) 17 print(response.text[:20]) 18 print('----------------------------------------------') 19 ''' 20 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt19.py 21 <Response [200]> 22 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 23 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC144A1F6BEA823FF4F5:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC144A1F6BEA823FF4F5 for .baidu.com/>, <Cookie H_PS_PSSID=1444_21081_27509 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 24 <!DOCTYPE html> 25 <!-- 26 ---------------------------------------------- 27 <Response [200]> 28 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 29 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC14FA9EECCB0280B074:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC14FA9EECCB0280B074 for .baidu.com/>, <Cookie H_PS_PSSID=26523_1469_25810_21098_26350_22073 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 30 <!DOCTYPE html> 31 <!-- 32 ---------------------------------------------- 33 34 Process finished with exit code 0 35 36 ''' 37 38 with session: 39 for url in urls: 40 response = session.get(url, headers={'User-agent':ua}) 41 # response = requests.request('GET', url, headers={'User-agent':ua}) 42 print(response) 43  with response: 44 print(response.request.headers) 45 print(response.cookies) 46 print(response.text[:20]) 47 print('----------------------------------------------') 48 ''' 49 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt19.py 50 <Response [200]> 51 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} 52 <RequestsCookieJar[<Cookie BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1 for .baidu.com/>, <Cookie BIDUPSID=5A320955507582B839E723DB6F55B2BD for .baidu.com/>, <Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie PSTM=1543981366 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 53 <!DOCTYPE html> 54 <!-- 55 ---------------------------------------------- 56 <Response [200]> 第二次訪問,帶上了cookie 57 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1; BIDUPSID=5A320955507582B839E723DB6F55B2BD; H_PS_PSSID=1434_21091_18559_27245_27509; PSTM=1543981366; delPer=0; BDSVRTM=0; BD_HOME=0'} 58 <RequestsCookieJar[<Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]> 59 <!DOCTYPE html> 60 <!-- 61 ---------------------------------------------- 62 63 Process finished with exit code 0 64 65 '''