1. 程式人生 > 其它 >【網路爬蟲學習】第一個Python爬蟲程式 & 編碼與解碼詳解 & Pythonの實現

【網路爬蟲學習】第一個Python爬蟲程式 & 編碼與解碼詳解 & Pythonの實現

本節編寫一個最簡單的爬蟲程式,作為學習 Python 爬蟲前的開胃小菜。

下面使用 Python 內建的 urllib 庫獲取網頁的 html 資訊。注意,urllib 庫屬於 Python 的標準庫模組,無須單獨安裝,它是 Python 爬蟲的常用模組。

獲取網頁html資訊

1) 獲取響應物件

向百度(http://www.baidu.com/)發起請求,獲取百度首頁的 HTML 資訊,程式碼如下:

# 導包,發起請求使用urllib庫的request請求模組
import urllib.request

# urlopen()向URL發請求,返回響應物件,注意url必須完整
responese = urllib.request.urlopen('https://www.baidu.com/')
print(responese)

上述程式碼會返回百度首頁的響應物件, 其中 urlopen() 表示開啟一個網頁地址。

注意:請求的 url 必須帶有 http 或者 https 傳輸協議。

輸出結果,如下所示:

<http.client.HTTPResponse object at 0x032F0F90>

上述程式碼也有另外一種導包方式,也就是使用 from,程式碼如下所示:

# 發起請求使用urllib庫的request請求模組
from urllib import request

responese = request.urlopen('https://www.baidu.com/')
print(responese)

2) 輸出HTML資訊

在上述程式碼的基礎上繼續編寫如下程式碼:

# 提取響應內容
html = responese.read().decode('utf-8')
# 列印響應內容
print(html)

輸出結果如下,由於篇幅過長,此處只做了簡單顯示:

<http.client.HTTPResponse object at 0x03678E68>
<html>
<head>
        <script>
                location.replace(location.href.replace("https://","http://"));
        </script>
</head>
<body>
        <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>   
</body>
</html>

通過呼叫 response 響應物件的 read() 方法提取 HTML 資訊,該方法返回的結果是位元組串型別(bytes),因此需要使用 decode() 轉換為字串。程式完整的程式碼程式如下:

# 發起請求使用urllib庫的request請求模組
from urllib import request

responese = request.urlopen('https://www.baidu.com/')
print(responese)

# 提取響應內容
html = responese.read().decode('utf-8')
# 列印響應內容
print(html)

通過上述程式碼獲取了百度首頁的 html 資訊,這是最簡單、最初級的爬蟲程式。後續我們還學習如何分析網頁結構、解析網頁資料,以及儲存資料等。

常用方法

在本節您認識了第一個爬蟲庫 urllib,下面關於 urllib 做簡單總結。

1) urlopen()

表示向網站發起請求並獲取響應物件,如下所示:

urllib.request.urlopen(url,timeout)

urlopen() 有兩個引數,說明如下:

  • url:表示要爬取資料的 url 地址。
  • timeout:設定等待超時時間,指定時間內未得到響應則丟擲超時異常。

2) Request()

該方法用於建立請求物件、包裝請求頭,比如重構 User-Agent(即使用者代理,指使用者使用的瀏覽器)使程式更像人類的請求,而非機器。重構 User-Agent 是爬蟲和反爬蟲鬥爭的第一步。在下一節會做詳細介紹。

urllib.request.Request(url, headers)

引數說明如下:

  • url:請求的URL地址。
  • headers:重構請求頭。

3) html響應物件方法

bytes = response.read() # read()返回結果為 bytes 資料型別
string = response.read().decode() # decode()將位元組串轉換為 string 型別
url = response.geturl() # 返回響應物件的URL地址
code = response.getcode() # 返回請求時的HTTP響應碼

4) 編碼解碼操作

#字串轉換為位元組碼
string.encode("utf-8") 
#位元組碼轉換為字串
bytes.decode("utf-8") 

\[QAQ \]

既然這裡提到了解碼以及編碼就稍微進階一下...

請注意,本部分來自 阮一峰的網路日誌 & C語言中文網的URL編碼/解碼詳解

URL就是網址,只要上網,就一定會用到。

一般來說,URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字和符號。比如,世界上有英文字母的網址"http://www.abc.com",但是沒有希臘字母的網址"http://www.aβγ.com"(讀作阿爾法-貝塔-伽瑪.com)。這是因為網路標準RFC 1738做了硬性規定:

"...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."

"只有字母和數字[0-9a-zA-Z]、一些特殊符號"$-_.+!*'(),"[不包括雙引號]、以及某些保留字,才可以不經過編碼直接用於URL。"

關於漢字部分的詳解請移步自:Here 進行學習,這裡不多介紹了。

當 URL 路徑或者查詢引數中,帶有中文或者特殊字元的時候,就需要對 URL 進行編碼(採用十六進位制編碼格式)。URL 編碼的原則是使用安全字元去表示那些不安全的字元。

PS:安全字元,指的是沒有特殊用途或者特殊意義的字元。

URL基本組成

URL 是由一些簡單的元件構成,比如協議、域名、埠號、路徑和查詢字串等,示例如下:

https://www.cnblogs.com/RioTian/index?param=10

路徑和查詢字串之間使用問號?隔開。上述示例的域名為 www.cnblogs.com/RioTian/,路徑為 index,查詢字串為 param=10。

URL 中規定了一些具有特殊意義的字元,常被用來分隔兩個不同的 URL 元件,這些字元被稱為保留字元。例如:

  • 冒號:用於分隔協議和主機元件,斜槓用於分隔主機和路徑
  • ?:用於分隔路徑和查詢引數等。
  • =用於表示查詢引數中的鍵值對。
  • &符號用於分隔查詢多個鍵值對。
其餘常用的保留字元有:/ . ... # @ $ + ; %

哪些字元需要編碼

URL 之所以需要編碼,是因為 URL 中的某些字元會引起歧義,比如 URL 查詢引數中包含了”&”或者”%”就會造成伺服器解析錯誤;再比如,URL 的編碼格式採用的是 ASCII 碼而非 Unicode 格式,這表明 URL 中不允許包含任何非 ASCII 字元(比如中文),否則就會造成 URL 解析錯誤。

URL 編碼協議規定(RFC3986 協議):URL 中只允許使用 ASCII 字符集可以顯示的字元,比如英文字母、數字、和- _ . ~ ! *這 6 個特殊字元。當在 URL 中使用不屬於 ASCII 字符集的字元時,就要使用特殊的符號對該字元進行編碼,比如空格需要用%20來表示。

除了無法顯示的字元需要編碼外,還需要對 URL 中的部分保留字元不安全字元進行編碼。下面列舉了部分不安全字元:

[ ] < > " "  { } | \ ^ * · ‘ ’ 等

下面示例,查詢字串中包含一些特殊字元,這些特殊字元不需要編碼:

http://www.biancheng.net/index?param=10!*&param1=20!-~_

下表對 URL 中部分保留字元和不安全字元進行了說明:

字元 (URL特殊字元編碼) 含義 十六進位制值編碼
+ URL 中 + 號表示空格 %2B
空格 URL中的空格可以編碼為 + 號或者 %20 %20
/ 分隔目錄和子目錄 %2F
? 分隔實際的 URL 和引數 %3F
% 指定特殊字元 %25
# 表示書籤 %23
& URL 中指定的引數間的分隔符 %26
= URL 中指定引數的值 %3D

下面簡單總結一下,哪些字元需要編碼,分為以下三種情況:

  • ASCII 表中沒有對應的可顯示字元,例如,漢字。
  • 不安全字元,包括:# ”% <> [] {} | \ ^ ` 。
  • 部分保留字元,即 & / : ; = ? @ 。

Python實現編碼與解碼

Python 的標準庫urllib.parse模組中提供了用來編碼和解碼的方法,分別是 urlencode() 與 unquote() 方法。

方法 說明
urlencode() 該方法實現了對 url 地址的編碼操作
unquote() 該方法將編碼後的 url 地址進行還原,被稱為解碼

1) 編碼urlencode()

下面以百度搜索為例進行講解。首先開啟百度首頁,在搜尋框中輸入“爬蟲”,然後點選“百度一下”。當搜尋結果顯示後,此時位址列的 URL 資訊,如下所示:

https://www.baidu.com/s?wd=爬蟲&rsv_spt=1&rsv_iqid=0xa3ca348c0001a2ab&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_dl=ib&rsv_sug3=8&rsv_sug1=7&rsv_sug7=101

可以看出 URL 中有很多的查詢字串,而第一個查詢字串就是“wd=爬蟲”,其中 wd 表示查詢字串的鍵,而“爬蟲”則代表您輸入的值。

在網頁位址列中刪除多餘的查詢字串,最後顯示的 URL 如下所示:

https://www.baidu.com/s?wd=爬蟲

使用搜索修改後的 URL 進行搜尋,依然會得到相同頁面。因此可知“wd”引數是百度搜索的關鍵查詢引數。下面編寫爬蟲程式對 “wd=爬蟲”進行編碼,如下所示:

from urllib import request
from urllib import parse

# 構建查詢字串字典
query_string = {'wd': '爬蟲'}
# 呼叫parse模組的urlencode()進行編碼
result = parse.urlencode(query_string)
# 使用format函式格式化字串,拼接url地址
url = 'http://www.baidu.com/s?{}'.format(result)
print(url)

輸出結果,如下所示:

wd=%E7%88%AC%E8%99%AB
http://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB

編碼後的 URL 地址依然可以通過地網頁址欄實現搜尋功能。

除了使用 urlencode() 方法之外,也可以使用 quote(string) 方法實現編碼,程式碼如下:

from urllib import parse

# 注意url的書寫格式,和 urlencode存在不同
url = 'http://www.baidu.com/s?wd={}'
word = input('請輸入要搜尋的內容: ')
# quote() 只能對字串編碼
query_string = parse.quote(word)
print(url.format(query_string))

輸出結果如下:

輸入:請輸入要搜尋的內容:RioTian部落格園
輸出:http://www.baidu.com/s?wd=RioTian%E5%8D%9A%E5%AE%A2%E5%9B%AD

編碼後的 URL 地址依然可以通過地網頁址欄實現搜尋功能。

除了使用 urlencode() 方法之外,也可以使用 quote(string) 方法實現編碼,程式碼如下:

from urllib import parse

# 注意url的書寫格式,和 urlencode存在不同
url = 'http://www.baidu.com/s?wd={}'
word = input('請輸入要搜尋的內容: ')
# quote() 只能對字串編碼
query_string = parse.quote(word)
print(url.format(query_string))

輸出結果如下:

請輸入要搜尋的內容: RioTian
http://www.baidu.com/s?wd=RioTian

注意:quote() 只能對字串編碼,而 urlencode() 可以直接對查詢字串字典進行編碼。因此在定義 URL 時,需要注意兩者之間的差異。方法如下:

# urllib.parse
urllib.parse.urlencode({'key':'value'}) #字典
urllib.parse.quote(string) #字串

2) 解碼unquote(string)

解碼是對編碼後的 URL 進行還原的一種操作,示例程式碼如下:

from urllib import parse

string = '%E7%88%AC%E8%99%AB'
print(parse.unquote(string))

輸出結果:

爬蟲

3) URL地址拼接方式

最後,給大家介紹三種拼接 URL 地址的方法。除了使用 format() 函式外,還可以使用字串相加,以及字串佔位符,總結如下:

似乎以前也寫過(霧QAQ)

# 1、字串相加
baseurl = 'http://www.baidu.com/s?'
params = 'wd=%E7%88%AC%E8%99%AB'
url = baseurl + params

# 2、字串格式化(佔位符)
params = 'wd=%E7%88%AC%E8%99%AB'
url = 'http://www.baidu.com/s?%s' % params

# 3、format()方法
url = 'http://www.baidu.com/s?{}'
params = 'wd=%E7%88%AC%E8%99%AB'
url = url.format(params)

The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。