遇到一些真的很難爬的網站,例如google arts & culture,很難直接用request 去攻破他。你也可以考慮使用Selenium,這是一個瀏覽器模擬工具,你可能想說,連瀏覽器都要模擬阿? 阿 對阿~ 你明明有手機還不是在電腦上用手機模擬器打手游,為什麼瀏覽器不能有模擬器。總之,你可以把寫好的模擬器腳本給Selenium來爬取你要的訊息。
Selenium的優勢是: 使用瀏覽器執行js,不需要不斷測試攻破點,缺點是慢。
一、 安裝
這裡是教Windows Anaconda 的Selenium安裝,使用默認瀏覽器是chrome。第一步是打開chrome說明查看chrome版本。
接下來到 https://sites.google.com/a/chromium.org/chromedriver/home 下載相對應chrome版本模擬器,win32版。(你用linux就下linux版同理mac),解壓後會得到chromedriver
查看你目前env的python路徑:
import sys
sys.executable
把chromedriver放在環境路徑下。對我來說也就是跟上面路徑的python.exe放在同一個資料夾內。
然後安裝selenium
conda install -c anaconda selenium
測試一下是否能成功自動化打開chrome
from selenium import webdriver
browser = webdriver.Chrome()
如果成功可以跳出一個新的chrome頁面。
然後推薦一個chrome套件,叫做selenium IDE,可以快速建立腳本。
二、 基本Selenium操作
我們來模擬登入吧,爬取Google Arts & Culture吧! Google Art & Culture內的國立故宮博物館有線上展示近800個展品。但是在瀏覽展品時他不會一次全部load近來,而是當你點擊向右才會展出更多展覽品。如果我們想要把所有展品圖片、文字爬下來該怎麼做呢?
先打開Selenium IDE,開啟故宮的url
此時會跳出一個新視窗,Selenium IDE會記錄下你在瀏覽器上的任何操作。試著點擊向右的按鍵。Selenium IDE會出現你操作過的內容,下圖其中click的部分就是點擊右鍵的紀錄(黃)。
這是IDE自動生成的,可以看到點擊target是由css來定位的。所以我們只要利用Selenium不斷點擊右邊直到無法點擊為止再將全部圖片連結抓下來即可。IED也可以自動生成程式,對專案export後(python pytest)
可以看到一個寫好的腳本,根據腳本我們就可以自己寫一個屬於自己的Selenium了。不過這裡我還是先不參考腳本寫,首先你要先將selenium載入。selenium find element支援xpath、css、class等多種寫法,這裡使用xpath寫法,要換種寫法基本上把By.後面換掉即可。
from selenium import webdriver
from selenium.webdriver.common.by import Bydriver = webdriver.Chrome() #打開Selenium Chrome# 進入故宮網頁
driver.get("https://artsandculture.google.com/partner/national-palace-museum-taiwan")# 右鍵xpath
right_arrow_xpath ='//span[@id="exp_tab_popular"]//div[@data-gaaction="rightArrow"]'# 連點右鍵10下
for _ in range(10):
driver.find_element(By.XPATH,right_arrow_xpath).click()
你會發現明明點了10下,怎麼網頁只有動一下呢? 這是因為你點太快了,有兩種選擇:
- 加上等待時間 time.sleep(second)
- 使用WebDriverWait
我們這裡先用sleep吧,接下來後面再使用WebDriverWait。
import time# 直到右鍵消失,無法點擊錯誤出現代表已經右到底了
while(True):
try:
driver.find_element(By.XPATH,right_arrow_xpath).click()
time.sleep(0.3)
except:
print("ElementClickInterceptedException")
break
然後你就可以看著他很舒壓的向右跑
跑完後可以用F12查看發現所有的展品連結都是包覆再wcg9yf內,用selenium簡單的抓出來。
要得到a的attribute (link)程式如下:
a_xpath = '//div[@class="wcg9yf"]//a'# 注意是find_elements 因為有很多個 回傳list
a_nodes = driver.find_elements(By.XPATH,a_xpath)links = []
for node in a_nodes:
links.append(node.get_attribute("href"))
接著我們可以遍歷這些links來取得這些展覽品的名稱與圖片,這裡我們介紹一下WebDriverWait,WebDriverWait是避免網頁element未被加載完成就被爬取而導致錯誤(ajax),他會等待node生成完畢後再調用接下來的爬取程式。
我們一進入這些links時圖片的node還未必產生了,直接爬取會報錯,但是我們又無法確定要等待多久才會產生(取決於網路),所以使用WebDriverWait來等待。
我們先來看看圖片的結構長甚麼樣子?
import os
img_dir = "./imgs/"# 如果資料夾不存在就新增
if(os.path.isdir(img_dir) == False):
os.mkdir(img_dir)from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECimg_xpath = '//img[@class="XkWAb-LmsqOc XkWAb-Iak2Lc"]'
title_xpath = '//h1[@class="EReoAc"]'for link in links:
driver.get(link)
try:
# 最多等待 img_xpath 10秒,超過10秒拋出ExpectedCondition
# 如果10秒內出現了則立即回傳給element
# google art&culture 是 bolb比較難用requests爬
# 所以我們用 selenium連到後截圖保存
element = WebDriverWait(driver, 10). \until(EC.presence_of_element_located((By.XPATH,img_xpath)))
img_link = element.get_attribute("src")
title = driver.find_element(By.XPATH,title_xpath).text
# 截圖保存
driver.get(img_link)
driver.save_screenshot(img_dir+title+".png")
except:
continue
如此一來就正確爬到圖片了。
你可能說怎麼一堆黑邊,這是Google Art & Culture的響應式預留黑邊。偷偷說,你可以用opencv findContours把黑邊去掉。不過這就不在這篇的討論費為內了。