[Python爬蟲] 03. requests HTTP GET&POST

 · 9 mins read

本篇介紹如何對目標網頁的 Server 發出 HTTP requests,需要一點通訊協定的基礎,可參考本文 01. Http 協定



win7 開發環境

  • python 3.5
  • 安裝 requests 模組

      $ pip3 install requests2
    



requests.Request

  • requests.request:使用者定義的 Request 物件,使用在產生 PreparedRequest 物件。

      # POST
      requests.request("POST", url, data={'Data':json.dumps(payload)})
      # GET
      req = requests.Request('GET', 'http://httpbin.org/get')
      req.prepare()
      >>>
      <PreparedRequest [GET]>
    



GET

GET 基本使用

  • requests.get:使用 GET 方式下載普通網頁。

      import requests
    
      r = requests.get('https://www.google.com.tw/')
    
  • .text:輸出回應的內容(str 型態)。

      import requests
    
      r = requests.get('https://www.google.com.tw/')
      print (r.text)
    
      >>> 
      u'{"type":"User"...'
    
  • .json():輸出成 json 格式

      import requests
    
      r = requests.get('https://www.google.com.tw/')
      print (r.json())
    
      >>> 
      {u'private_gists': 419, u'total_private_repos': 77, ...}
    
  • .headers:取得 headers 的 content-type。

      r.headers['content-type']
    
      >>>
      'application/json; charset=utf8'
    
  • .encoding:設定編碼。

      r.encoding = 'utf-8'
      r.encoding = 'cp950'
      r.encoding = 'utf8'
    
  • .status_code:伺服器回應的狀態碼。

      print(r.status_code)
    
      >>> 
      200
    
  • 檢查狀態碼(status_code)是否 OK

      if r.status_code == requests.codes.ok:
          print("OK")
    

傳遞參數

  • URL 查詢參數。

      payload = {'key1': 'value1', 'key2': 'value2'}
      payload = {'key1': 'value1', 'key2': ['value2', 'value3']} #也可以傳遞列表
        
      # 將查詢參數加入GET請求中
      r = requests.get('http://httpbin.org/get', params = payload)
      print(r.url)
      >>>
      http://httpbin.org/get?key2=value2&key1=value1
    
  • headers 傳遞:有些網站會阻擋爬蟲程式,若傳送的 header 不正常可能會被對方 server 組檔,所以在進入網站時,模擬瀏覽器生成 header,將自己偽裝成一個正常的客戶傳遞。

      headers = {'user-agent': 'my-app/0.0.1'} # 自訂表頭
      r = requests.get('http://httpbin.org/get', headers = my_headers)
    
  • cookies 傳遞。

      r = requests.get('http://httpbin.org/cookies', cookies=dict(cookies_are='working'))
      r.text
      >>>
      '{"cookies": {"cookies_are": "working"}}'
    
  • auth:指定帳號與密碼。

      r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
    



POST

POST 請求

  • requests.post:將資料加入 POST 請求中。

      # 資料
      my_data = {'key1': 'value1', 'key2': 'value2'}
      # 若是具有重複鍵值的資料
      my_data = (('key1', 'value1'), ('key1', 'value2'))
        
      #參數:url/POST的東西
      r = requests.post('http://httpbin.org/post', data = my_data)  
    
  • json.dumps:傳遞 json 格式資料。

      import json
    
      url = 'https://api.github.com/some/endpoint'
      payload = {'some': 'data'}
        
      r = requests.post(url, data=json.dumps(payload)) #將Python對象編碼成JSON字符串>data={"some": "data"}
      # 或者
      r = requests.post(url, json=payload)
    

上傳檔案

  • open('filename', 'rb')

      # 要上傳的檔案
      my_files = {'my_filename': open('my_file.docx', 'rb')} 
      # 或是配置files,filename, content_type and headers
      my_files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
      my_files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
    
      # 將檔案加入POST請求中
      r = requests.post('http://httpbin.org/post', files = my_files)
    



進階應用

Session

  • Session()

      s = requests.Session()
      s.get('http://httpbin.org/get')
      s.close()
    
  • 拿 cookie 和 使用 cookie

      # 拿cookie
      login_url = "http://mg.zzz.net/Member/DoLogin"
      payload = {'account': 'cleo', 'password': 'Aa123456'}
      headers = {
          'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
          'Cache-Control': "no-cache",
          }
    
      response = requests.post(login_url, data=payload, headers=headers) 
      # print(response.text)
      cookies = response.cookies.get_dict()
    
      # 傳入cookie
      GetPeriod_url = ('http://mg.zzz.net/Period/GetPeriodList/?LotEnum=5&pageindex='+str(p))
      headers = {
          'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
          'Cache-Control': "no-cache",
          }
    
      response = requests.request("GET", GetPeriod_url, headers=headers, cookies=cookies)
      r = response.json()
    
  • requests 取出 cookies 的資料。

      s = requests.Session()
        
      s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
      r = s.get('http://httpbin.org/cookies')
      print(r.text)
      >>>
      '{"cookies": {"sessioncookie": "123456789"}}'
    
  • cookies:將 cookies 放進 GET 請求中送給伺服器。

      # 設定 cookie
      my_cookies = dict(my_cookie_name='G. T. Wang')
        
      # 將cookie加入GET請求
      r = requests.get("http://httpbin.org/cookies", cookies = my_cookies)
    

等待時間

  • elapsed:送出 request 到收到 response 的時間。

      r = requests.get('http://httpbin.org')
      r.elapsed
      >>>
      datetime.timedelta(0, 0, 687039)
    
  • timeout:等待時間。

      # 設定timeout 3秒無回應則放棄
      requests.get('http://github.com/', timeout = 3)
      # 永久等待
      requests.get('https://github.com/', timeout=None) 
    

重導向

  • allow_redirects:禁用導向處理。

      requests.get('http://httpbin.org/redirect/6', allow_redirects=False)
    
  • history:重導向的記錄。

      r = requests.get('http://httpbin.org/redirect/3')
      r.history
      >>>
      [<Response [302]>, <Response [302]>, <Response [302]>]
    

代理伺服器

  • proxies:可指定特定網址使用特定代理。

      proxies = {
          'http://10.20.1.128': 'http://10.10.1.10:5323'
          "http": "http://user:pass@10.10.1.10:3128/",
          "https": "http://10.10.1.10:1080",
      }
      requests.get("http://example.org", proxies=proxies)
    

SSL

  • verify(預設 True):要想檢查某個主機的 SSL 證書,Requests 可以為 HTTPS 請求驗證 SSL 證書,就像 web 瀏覽器一樣。

      # 忽略驗證SSL憑證檢查
      requests.get('https://httpbin.org/', verify=False) 
      >>>
      <Response [200]>
    
      # 驗證SSL,需要有證書才能正確回應
      requests.get('https://github.com', verify=True) 
      >>>
      <Response [200]>
    
  • verify & cert 私有證書。

      # 私有證書
      requests.get('https://github.com', verify='/path/to/certfile') 
    
      # 本機證書,私有 key 必須是解密狀態
      requests.get('https://kennethreitz.com', cert=('/path/server.crt', '/path/key'))
      requests.get('https://kennethreitz.com', cert='/path/server.pem')
    

解決回應編碼

  • encode & decode

      (post_response.text.encode(sys.stdin.encoding, "replace").decode(sys.stdin.encoding))
    



Exception

  • requests.RequestException:任意的異常。
  • requests.ConnectionError:連接異常。
  • requests.HTTPError:HTTP 異常。
  • requests.URLRequired:需提供正確的網址。
  • requests.TooManyRedirects:太多重新轉向。
  • requests.ConnectTimeout:連接超時,可試著重新再連接。
  • requests.ReadTimeout:時間內未送任何資料。
  • requests.Timeout:超時,ConnectTimeout、ReadTimeout 都會被抓到。



ref: