- 原文地址:30-minute Python Web Scraper
- 原文作者:Angelos Chalaris
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:kezhenxu94
- 校對者:luochen1992 leviding
一直想用 Python 和 Selenium 寫一個網頁爬蟲,但一直都沒去實現。直到幾天前我才決定動手實現它。寫程式碼從 Unsplash 網站上抓取一些漂亮的圖片,這看起來好像是非常艱鉅的事情,但實際上卻是極其簡單。
圖片來源:Blake Connally 釋出於 Unsplash.com
簡單圖片爬蟲的原料
- Python (3.6.3 或以上)
- Pycharm (社群版就已經足夠了)
- pip install requests Pillow selenium
- geckodriver (具體見下文)
- Mozlla Firefox (如果你沒有安裝過的話)
- 正常的網路連線(顯然需要的)
- 你寶貴的 30 分鐘(也許更少)
簡單圖片爬蟲的菜譜
以上的所有都安裝好了?棒!在我們繼續開始寫程式碼前,我先來解釋一下以上這些原料都是用來幹什麼的。
我們首先要做的是利用 Selenium webdriver 和 geckodriver 來為我們開啟一個瀏覽器視窗。首先,在 Pycharm 中新建一個專案,根據你的作業系統下載最新版的 geckodriver,將其解壓並把 geckodriver 檔案拖到專案資料夾中。Geckodriver 本質上就是一個能讓 Selenium 控制 Firefox 的工具,因此我們的專案需要它來讓瀏覽器幫我們做一些事。
接下來我們要做的事就是從 Selenium 中匯入 webdriver 到我們的程式碼中,然後連線到我們想爬取的 URL 地址。說做就做:
from selenium import webdriver
# 我們想要瀏覽的 URL 連結
url = "https://unsplash.com"
# 使用 Selenium 的 webdriver 來開啟這個頁面
driver = webdriver.Firefox(executable_path=r'geckodriver.exe')
driver.get(url)
複製程式碼
開啟瀏覽器視窗到指定的 URL。
一個遠端控制的 Firefox 視窗。
相當容易對吧?如果以上所說你都正確完成了,你已經攻克了最難的那部分了,此時你應該看到一個類似於以上圖片所示的瀏覽器視窗。
接下來我們就應該向下滾動以便更多的圖片可以載入出來,然後我們才能夠將它們下載下來。我們還想再等幾秒鐘,以便萬一網路連線太慢了導致圖片沒有完全載入出來。由於 Unsplash 網站是使用 React 構建的,等個 5 秒鐘似乎已經足夠”慷慨”了,那就使用 Python 的 time
包等個 5 秒吧,我們還要使用一些 Javascript 程式碼來滾動網頁——我們將會用到 [window.scrollTo()](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
函式來實現這個功能。將以上所說的合併起來,最終你的程式碼應該像這樣:
import time
from selenium import webdriver
url = "https://unsplash.com"
driver = webdriver.Firefox(executable_path=r'geckodriver.exe')
driver.get(url)
# 向下滾動頁面並且等待 5 秒鐘
driver.execute_script("window.scrollTo(0,1000);")
time.sleep(5)
複製程式碼
滾動頁面並等待 5 秒鐘。
測試完以上程式碼後,你應該會看到瀏覽器的頁面稍微往下滾動了一些。下一步我們要做的就是找到我們要下載的那些圖片。在探索了一番 React 生成的程式碼之後,我發現了我們可以使用一個 CSS 選擇器來定位到網頁上畫廊的圖片。網頁上的佈局和程式碼在以後可能會發生改變,但目前我們可以使用 #gridMulti img
選擇器來獲得螢幕上可見的所有 <img>
元素。
我們可以通過 [find_elements_by_css_selector()](http://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.find_element_by_css_selector)
得到這些元素的一個列表,但我們想要的是這些元素的 src
屬性。我們可以遍歷這個列表並一一抽取出 src
來:
import time
from selenium import webdriver
url = "https://unsplash.com"
driver = webdriver.Firefox(executable_path=r'geckodriver.exe')
driver.get(url)
driver.execute_script("window.scrollTo(0,1000);")
time.sleep(5)
# 選擇圖片元素並列印出他們的 URL
image_elements = driver.find_elements_by_css_selector("#gridMulti img")
for image_element in image_elements:
image_url = image_element.get_attribute("src")
print(image_url)
複製程式碼
選擇圖片元素並獲得圖片 URL。
現在為了真正獲得我們找到的圖片,我們會使用 requests
庫和 PIL
的部分功能,也就是 Image
。我們還會用到 io
庫裡面的 BytesIO
來將圖片寫到資料夾 ./images/
中(在專案資料夾中建立)。現在把這些都一起做了,我們要先往每張圖片的 URL 連結傳送一個 HTTP GET 請求,然後使用 Image
和 BytesIO
來將返回的圖片儲存起來。以下是實現這個功能的其中一種方式:
import requests
import time
from selenium import webdriver
from PIL import Image
from io import BytesIO
url = "https://unsplash.com"
driver = webdriver.Firefox(executable_path=r'geckodriver.exe')
driver.get(url)
driver.execute_script("window.scrollTo(0,1000);")
time.sleep(5)
image_elements = driver.find_elements_by_css_selector("#gridMulti img")
i = 0
for image_element in image_elements:
image_url = image_element.get_attribute("src")
# 傳送一個 HTTP GET 請求,從響應內容中獲得圖片並將其儲存
image_object = requests.get(image_url)
image = Image.open(BytesIO(image_object.content))
image.save("./images/image" + str(i) + "." + image.format, image.format)
i += 1
複製程式碼
下載圖片。
這就是爬取一堆圖片所需要做的所有了。很顯然的是,除非你想隨便找些圖片素材來做個設計原型,否則這個小小的爬蟲用處可能不是很大。所以我花了點時間來優化它,加了些功能:
- 允許使用者通過指定一個命令列引數來指定搜尋查詢,還有一個數值引數指定向下滾動次數,這使得頁面可以顯示更多的圖片可供我們下載。
- 可以自定義的 CSS 選擇器。
- 基於搜尋查詢關鍵字的自定義結果資料夾。
- 通過截斷圖片的預覽圖連結來獲得全高清圖片。
- 基於圖片的 URL 給圖片檔案命名。
- 爬取最終結束後關閉瀏覽器。
你可以(你也應該)嘗試自己實現這些功能。全功能版本的爬蟲可以在這裡下載。記得要先按照文章開頭所說的,下載 geckodriver 然後連線到你的專案中。
不足之處,注意事項和未來優化項
整個專案是一個簡單的“驗證概念”,以弄清楚網頁爬蟲是如何做的,這也就意味著有很多東西可以做,來優化這個小工具:
- 沒有致謝圖片最開始的上傳者是個很不好的做法。Selenium 肯定是有能力處理這種情況的,那麼每個圖片都帶有作者的名字。
- Geckodriver 不應該被放在專案資料夾中,而是安裝在全域性環境下,並被放到
PATH
系統變數中。 - 搜尋功能可以輕易地擴充套件到多個查詢關鍵字,那麼下載很多型別圖片地過程就可以被簡化了。
- 預設瀏覽器可以用 Chrome 替代 Firefox,甚至可以用 PhantomJS 替代,這對這種型別的專案來說是更好的。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。