Python筆記:網頁資訊爬取簡介(一)

アハハハ君發表於2020-11-11

0. 內容簡介

這裡,我們在工作中遇到了一個實際問題,即:

  • 需要根據給出的淘寶網站連結獲取網頁中的sku標題以及主圖連結資訊。

藉此機會,我們剛好來學習一下網頁爬取相關的基礎技能,然後來解決上述問題。

更進一步的,我們也學一下如何下載網頁中的圖片、視訊等檔案。

不過需要注意的是,這裡,我們僅僅是作為一個學習性質的博文,內容也只是淺嘗輒止,僅用於對工作所需功能的簡單實現,並於大家進行分享和交流。

但如果後續有讀者基於本文進行了深度地學習,並用相關技術引起了相關的法律問題,請恕本文概不對其進行負責。

1. 網頁資訊獲取

首先,我們來看如何來獲得網頁資訊。

1. 莫煩教程方法

在參考連結1中莫煩的視訊教程中,他使用urllib庫的urllib.request.urlopen方法進行網頁內容的爬取。

具體命令為:

from urllib.request import urlopen

html = urlopen("https://detail.tmall.com/item.htm?spm=a230r.1.14.24.7acb2075Uiwtjj&id=601871231483&ns=1&abbucket=20").read()

但是在實際操作中,我們發現其中有許多的坑,主要包括:

  1. 兩次爬取命令執行就遇到了證照問題導致第二次獲取網頁內容失敗,出現下述報錯:
    URLError: <urlopen error [SSL: TLSV1_ALERT_INTERNAL_ERROR] tlsv1 alert internal error (_ssl.c:748)>
    
  2. 對html內容進行解碼時,由於網頁不一定按照utf-8進行編碼,因此,html.decode("utf-8")命令可能會出現如下報錯:
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 1742: invalid start byte
    

後續諮詢了公司裡面的資料組的朋友,發現前者的原因大概率是由於被網頁判斷為了爬蟲而被遮蔽了操作,後者則是由於網頁內容不支援utf-8編碼。

更好地獲取網頁內容的方式為使用requests加上header資訊的方式進行資料的爬取。

2. header資訊獲取

在普通的urlopen方法中,我們獲取的就是普通的流資訊,而無法知道http資訊中的內容的編碼方式等資訊,因此,就會出現上述解碼不知道該用什麼方式解碼的情況。

要做到這一點,我們需要在請求url的時候預先知道相關網站的頭資訊,這樣,我們才能夠在後續的操作中順利地對網頁內容進行解碼和分析。不過,更一般的情況下,我們事實上是在請求的過程中直接帶入頭資訊,從而做到在讀取網頁資訊的同時就進行網頁內容的解析。

因此,我們就需要考察一下如何來獲取網頁請求的頭資訊。

獲取頭資訊的方式我們可以通過獲取網頁的請求curl命令然後通過網上的轉換工具(比如參考連結6中的網站工具)來直接獲得請求命令。

我們開啟淘寶的網站連結,用F12快捷鍵開啟開發者工具欄,重新整理之後獲得的第一個請求就是該網站的直接的請求命令。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-vUjVMUDU-1605101642419)(…\imgs\python筆記:網站資訊爬取_fig01.png)]

右鍵該連結然後複製其curl地址,我們就可以獲得cmd命令列中直接請求的命令,然後使用上述線上轉換工具中轉換為python程式碼即可。

轉換之後我們就可以獲得相應的request程式碼,我們只取其中的頭資訊headers內容,刪除其中諸如cookies等無用資訊後給出樣例如下:

headers = {
    'authority': 'detail.tmall.com',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
    'referer': 'https://s.taobao.com/',
    'accept-language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8',
}

3. 使用requests獲取網頁內容

最後,我們來看如何來獲取網頁內的內容。

在莫煩的視訊中,網頁資訊獲取之後是一個資料流,我們首先要通過read()方法獲取其內容,然後通過decode方法將其轉換為可讀的編碼(如果其中存在中文內容的話)。

如果是按照莫煩教程中使用urllib中的urlopen方法的話,那麼我們還需要手動通過read以及decode函式對其進行內容的讀取,有點類似於python檔案的讀取方式。

但是,如果採用requests加頭資訊的方式的話,上述過程事實上已經在頭資訊中配置完成了,因此,我們直接獲得的結果就是我們可讀的結果。

事實上,上述curl轉換python的工具中本就會生成requests的呼叫請求。我們給出其呼叫程式碼如下:

import requests

headers = {
    'authority': 'detail.tmall.com',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
    'referer': 'https://s.taobao.com/',
    'accept-language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8'
}

params = (
    ('id', '629648945951'),
)

response = requests.get('https://detail.tmall.com/item.htm', headers=headers, params=params)

或者,我們可以更暴力一些,直接不通過params傳入引數,直接將網頁的url連結傳遞進去。

import requests

headers = {
    'authority': 'detail.tmall.com',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
    'referer': 'https://s.taobao.com/',
    'accept-language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8'
}

response = requests.get('https://detail.tmall.com/item.htm?spm=a230r.1.14.24.349e20750ClDZd&id=601871231483&ns=1&abbucket=20', headers=headers)

這樣,我們就能夠直接獲取到網頁中的內容資訊。

4. 網頁爬取失敗原因考察

實際在測試中,我們發現,即使使用頭資訊的方式,我們依然遇到了上述請求過於頻繁導致的問題。

下面,我們簡單對其進行一下分析,看看能否通過什麼方式繞開這個問題。

後續問了一下做資料的同事,發現這個問題並不是一個好解的問題,本質原因還是在於網頁的反爬機制,能夠被發現是爬蟲資訊的原因在於python的request請求行為與瀏覽器中實際發生的請求行為不一致。

具體而言,在瀏覽器中,每一次開啟網頁事實上都會觸發大量的相關網頁的請求,且瀏覽器的請求中cookie資訊會隨瀏覽行為的發生而發生改變,而request傳送的請求中cookie資訊往往是固定的,這就導致網頁可以由此發現請求到底來源於程式碼還是使用者的實際瀏覽器行為。

後續當然不是說沒有策略繞開這些反爬機制,但是整體來說這是一個和網站設計者鬥智鬥勇的過程,這裡僅僅作為一個普普通通的簡介性質的博文,就沒有必要研究的那麼深了。。。

2. 網頁資訊解析

下面,我們來考察網頁資訊的解析方法。

我們採用BeautifulSoup工具進行網頁內容的解析。

BeautifulSoup算是一個針對網頁資訊的高階版正規表示式封裝,我們可以不用寫複雜的正則匹配規則直接使用BeautifulSoup中的內建方法進行網頁資訊的獲取。

1. BeautifulSoup的安裝

首先,我們快速地給出以下BeautifulSoup的安裝過程,這個其實只需要pip安裝一下就行了,唯一需要注意的是,BeautifulSoup庫的pip包名稱為beautifulsoup4,其他都沒啥區別。

安裝完成之後,匯入的方式也需要注意一下,BeautifulSoup的匯入方式為:

from bs4 import BeautifulSoup

2. BeautifulSoup的使用

現在,我們來看一下BeautifulSoup的具體使用。

要詳細說明其使用方法,我們需要首先來看一下網頁中資訊內容的結構。

一般來說,網頁中的資訊都會長這個樣子:

<meta name="keywords" content="花花公子男裝夾克男春季新款休閒衝鋒衣連帽寬鬆潮流短款男士外套"/>

要獲取其中的資訊,BeautifulSoup的語法為:

soup = BeautifulSoup(html)
skutitle = soup.find("meta", {"name": "keywords"})["content"]

其中,meta為檔案樹的資訊欄位,後面的引數為過濾條件,最後取出content欄位的內容。

同樣的,我們可以快速地得到,獲取淘寶商品首圖的python命令為:

image = soup.find("img", {"id": "J_ImgBooth"})["src"]

3. 網頁中檔案的下載

最後,我們來看一下如何從網頁中下載檔案,比如說,如何獲取上述獲得的圖片。

給出獲得的圖片的url連結為:

url = "https://img.alicdn.com/imgextra/i4/1851041537/O1CN01qd5ZSB1NDzO4pNexv-1851041537.jpg_430x430q90.jpg"

這部分有兩種實現方式:

  1. 一種實現方式是使用wget庫將其作為一個檔案進行下載;
  2. 第二種是將其作為資料流進行讀取,然後寫入到一個檔案當中。

下面,我們分別來對其進行考察:

1. 將網頁中檔案作為資料流進行讀取後寫成一個檔案

給出程式碼樣例如下:

import requests 
url = 'https://img.alicdn.com/imgextra/i4/1851041537/O1CN01qd5ZSB1NDzO4pNexv-1851041537.jpg_430x430q90.jpg' 

with open("image.jpg", "wb") as fp:
    r = requests.get(url) 
    fp.write(r.content)

如此,我們即可從原始連結中獲取圖片檔案。

2. 使用wget方式直接進行檔案下載

如果在bash命令下,如果我們要獲取上述網路圖片,我們只需要使用下述命令即可:

wget https://img.alicdn.com/imgextra/i4/1851041537/O1CN01qd5ZSB1NDzO4pNexv-1851041537.jpg_430x430q90.jpg image.jpg

同樣的,在python中,同樣有一個wget庫,可以快速實現檔案的下載:

import wget

wget.download(url, "image.jpg")

3. 參考連結

  1. Python 爬蟲基礎教程 (莫煩 Scraping Tutorial)
  2. python使用wget下載網路檔案
  3. python下載檔案的三種方法
  4. Beautiful Soup 4.4.0 文件
  5. Curl轉python線上工具
  6. https://curl.trillworks.com/

相關文章