1. 概念
爬蟲不是動物,而是一種計算機程式。
這種程式有自己特定的功能,能按照使用者給定的一系列規則自行浏覽網際網路并擷取需要的資訊。此類程式被稱為 網絡爬蟲(web crawler) 或 網絡蜘蛛(spider)。 它具有智能分析能力,也稱為 機器人程式 。
爬蟲的應用應用領域:
如百度、谷歌等以搜尋為主的公司,就是利用其自行研發的爬蟲程式在網際網路上對網頁中的資料進行爬取、分析、歸類、存儲……再提供給使用者使用。 新聞聚合應用也是利用爬蟲程式爬取各新聞網站上的新聞資訊,進行分檢歸類後提供給使用者。
爬蟲程式可運用于各種需要資料分析的應用領域。如價格分析,根據商品關鍵字爬取各商城中商品價格,對價格進行比較、分析後展示給使用者一個直覺的對比表。
爬蟲程式從網絡上爬取資料時,需要遵守 Rebots 協定。
Rebots 協定是網站拟定的資源共享清單,規定爬蟲在本網站爬取資料時,哪些資源可以爬取,哪些資源不可以爬取。
爬蟲程式的工作流程:
- 确定目标網頁。此頁為起始頁或叫入口頁面。
- 擷取頁面的資料,通過某種方式(如正規表達式)擷取頁面中的相關資訊。并可提取頁面中連結,以遞歸方式繼續對頁面資料進行分析,提取。
- 将資訊持久化存儲,可備後續的處理。
2. Python 爬蟲子產品
爬蟲程式的核心邏輯之一便是通過網絡請求模式,下載下傳指定頁面的資料。
爬蟲程式的本質就是一個網絡應用程式。
Python 提供了豐富的庫或子產品可協助開發者快速開發此類網絡應用程式。
2.1 urllib 庫
urllib 庫是 python 内置庫,不需要另外安裝。完整的 urllib 庫包括如下 5 大子產品:
- urllib.request :可使用不同的協定發送請求包并擷取請求之後的響應結果。
- urllib.response :用來解析響應包資料。
- urllib.error: 包含了 urllib.request 産生的異常。
- urllib.parse: 用來解析和處理 URL。
- urllib.robotparse: 用來解析頁面的 robots.txt 檔案。
使用 urllib.request 子產品發送網絡請求:
import urllib.request
# 基于 https 協定的 url 位址
url = "https://www.cnblogs.com/guo-ke/p/15951196.html"
# 建構一個請求對象
req = urllib.request.Request(url)
# 使用 urlopen 方法發送請求包
with urllib.request.urlopen(req) as resp:
# 解析資料
data = resp.read()
print(data.decode())
複制代碼
- urllib.request.Request() 類說明:建構請求包。
類原型聲明:
class Request:
def __init__(self, url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None):
#…… 其它代碼塊
複制代碼
構造方法參數說明
- url: 要請求的 url 位址 。
- data: data 必須是bytes(位元組流)類型,如果是字典,可以用 urllib.parse 子產品裡的 urlencode( ) 編碼
- headers: headers 是一個字典類型,用來描述請求頭資訊。
- 可在構造方法中指定,也可以通過調用 add_header( ) 方法添加
- 預設 User-Agent 是 Python-urllib
- origin_req_host: 指定請求方的 host 名稱或者 ip 位址。
- unverifiable:設定網頁是否需要驗證,預設是 False。
- method: 用來指定請求使用的方法,如 **GET、POST 或 PUT ** 等。
很多網站具有反爬蟲設定,除了浏覽器之外的通路均認定為非法請求。是以爬蟲程式需要把自己僞裝成浏覽器。
from urllib import request, parse
url = 'http://www.guo-ke.com/post'
headers = {
# 僞裝成谷歌浏覽器
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
'Host': 'guo-ke.org'
}
dict = {
'name': 'guoke',
'key':'python'
}
# 資料必須是位元組流
data = bytes(parse.urlencode(dict), encoding='utf8')
'''
# 轉換成 URL 格式的字元串
data = parse.urlencode(dict)
# 編碼成位元組流資料
data = data.encode()
'''
request = request.Request(url=url, data=data, headers=headers, method='POST')
# req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36')
with request.urlopen(req) as response:
res=(response.read()
print(res.decode('utf-8'))
複制代碼
Tip: 當使用了 data 參數或指定 method="POST" 則為POST 請求。
GET 請求也能附加請求參數:www.baidu.com/s?wd=java
- urllib.request.urlopen( ) 方法說明:發送網絡請求。
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
*, cafile=None, capath=None, cadefault=False, context=None):
複制代碼
參數說明:
- url: 可以接收一個 URL 字元串 或一個 urllib.request.Request 對象。
- data: POST 請求時的資料,GET 請求設定為 None。
- timeout: 設定網站的通路逾時時間。僅僅用于使用 HTTP、HTTPS、FTP 協定請求連接配接時。
- cafile、capath: 當使用 HTTPS 請求時,用來指定 CA 數字證書。
- cafile 指定數字證書檔案。
- capath 指定包含的數字認證檔案的目錄。
傳回類型說明: 無論使用何種協定發送請求後傳回的對象都會包括 3 個通用方法。
- geturl( ) 傳回請求的資源URL。
- info( ) 傳回中繼資料資訊,如消息頭。
- getcode( ) 傳回響應的狀态碼. 如果有錯誤則會抛出 URLError 異常。
當使用 http 或 https 協定請求後傳回的是一個 http.client.HTTPResponse 對象,此對象除了上面的 3 個方法,還包括:
- read( ): 擷取響應傳回的 bytes 類型資料,隻能使用一次,輸出時需要使用 decode() 解碼。
- getheaders( ): 擷取傳回的響應頭資訊。
使用 urllib.request 下載下傳一張圖檔:
爬蟲程式強大之處在于能批量、遞歸下載下傳使用者所需要的資料,一個強大的邏輯背後的思想可能就是一個簡單的原理支撐的。我們可以先試着下載下傳一張圖檔以小窺大。
import urllib.request
# 圖檔URL
url = "https://img2022.cnblogs.com/blog/2749732/202202/2749732-20220222195931956-448995015.jpg"
with urllib.request.urlopen(url) as resp:
data = resp.read()
with open("d:/my_file.jpg", "wb") as f:
f.write(data)
複制代碼
打開對應盤符,可以查閱到圖檔已經下載下傳成功。
urllib.request 還提供有一個更友善的 urlretrieve( ) 方法。可直接以檔案方式存儲下載下傳下來的位元組流資料。
from urllib import request
url = "https://img2022.cnblogs.com/blog/2749732/202202/2749732-20220222195931956-448995015.jpg"
# urlretrieve() 方法傳入的第二個參數為檔案儲存的位置,以及檔案名。
request.urlretrieve(url, 'd:/temp.jpg')
複制代碼
2.2. requests 庫
requests 是基于urllib 編寫的第三方庫,使用時,需要下載下傳安裝:
pip3 install requests
複制代碼
主要提供了 2 個方法:
1. get( ) 方法用來發送 GET 請求。
def get(url, params=None, **kwargs):
#……
複制代碼
- url:需要請求的 url 資源(字元串類型)。
- params:查詢資料,可以是字典、清單、元組、位元組類型。
- kwargs:以鍵值對描述的請求消息頭參數。
基本 GET 使用:
import requests
# 用get方式發送請求并獲得響應
response = requests.get('https://www.cnblogs.com/guo-ke/p/15925214.html')
# 用text檢視響應内容
print(response.text)
複制代碼
帶參數 get 請求
import requests
response = requests.get('https://www.baidu.com/s?wd=java')
# 将參數拼接到url後面,用問号分隔,參數間用&來分隔
print(response.text)
複制代碼
字典格式的參數
import requests
data = {
'wd': 'java'
}
response = requests.get('https://www.baidu.com/s', params=data)
# 用字典的形式傳遞給params參數,不需要自己寫url編碼
print(response.text)
複制代碼
GET 方法傳回一個 Responese 對象,此對象提供有相應屬性或方法解析響應包中的資料。
- response.encoding:擷取目前的編碼。
- response.encoding = 'utf-8':設定編碼。
- response.text:自動根據響應頭部的字元編碼進行解碼。
- response.content:以位元組形式(二進制)傳回。
- response.headers:以字典對象存儲伺服器響應頭,字典鍵不區分大小寫,若鍵不存在則傳回 None。
- response.status_code:響應狀态碼。
- response.raw:傳回原始響應體,也就是 urllib 的 response 對象,使用 response.raw.read()
- response.json() :Requests 中内置的JSON解碼器,以json形式傳回,前提傳回的内容確定是json格式的,不然解析出錯會抛異常。
下載下傳一張圖檔
import requests
#;圖檔位址
url = "https://img2022.cnblogs.com/blog/2749732/202202/2749732-20220222195931956-448995015.jpg"
#請求頭中繼資料
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
}
response = requests.get(url, headers=headers)
# 擷取位元組流資料
data = response.content
#儲存位元組流資料
with open("d:/test.jpg", "wb") as f:
f.write(data)
複制代碼
2. post() 方法:以 post 方式發送請求
def post(url, data=None, json=None, **kwargs):
複制代碼
- url:字元串類型的需要請求的 url 資源。
- data:發送資料,可以是字典、清單、元組、位元組類型
- json:json 格式的資料。
- kwargs:以鍵值對描述的請求頭參數。
基本使用方式
import requests
data={'name':'zhuzhu','age':'23'}
headers={
'User-Agent':'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
}
response=requests.post("http://httpbin.org/post",data=data,headers=headers)
#資料必須是json 封裝
print(response.json())
複制代碼
3. 總結
requests 在基于 urllib 編寫的第三方庫,相比較 urllib 使用起來更簡單。對其 API 介紹 ,本文隻做了些簡單描述。更多方法或使用可查閱文檔。