一、分析
淘寶頁面中的商品都是用js動态加載的,是以使用selenium子產品抓取内容
1.首先分析如何用關鍵字搜尋内容
2.打開浏覽器
3.然後分析頁面結構,抓取資訊
4.其次擷取商品具體資訊的話需要打開二級頁面
5.需要找到下一頁的按鈕用于模拟點選下一頁,進而擷取所有頁面的相關資訊
二、開始操作
1.首先分析如何用關鍵字搜尋内容
注意到頁面的規律為
https://s.taobao.com/search?q=關鍵字
是以可以使用代碼
url="https://s.taobao.com/search?q={kw}".format(kw=urllib.parse.quote("衣服"))
這裡的衣服是我随便打的資料,在應用到scrapy架構中可以使用變量代替
2. 打開浏覽器
測試階段需要看浏覽器具體做了什麼操作,是以我使用了用顯示方式打開:
from selenium import webdriver
driver=webdriver.Chrome()
當程式沒有什麼問題了再用隐藏方式開啟浏覽器,這樣就不用加載浏覽器裡面的圖檔等資訊了,速度會快很多很多:
option=webdriver.ChromeOptions()
option.add_argument("headless")
driver = webdriver.Chrome(options=option)
擷取首頁面:
main_driver=driver.current_window_handle
3.然後分析頁面結構,抓取資訊
加載裡面所有商品,使用一個js讓他執行,移動垂直滾動條到最下面:
js="window.scrollTo(0,document.body.scrollHeight)"
driver.execute_script(js)
發現他的商品都放在這個div下,是以用goods儲存所有div
goods=driver.find_elements_by_xpath('//div[contains(@class,"J_MouserOnverReq")]')
開始周遊goods,這些是我要擷取的内容:
for good in goods:
price=good.find_element_by_xpath('.//div[2]/div[1]/div/strong').text
title=good.find_element_by_xpath('.//div[2]/div[2]/a').text
shop_name=good.find_element_by_xpath('.//div[2]/div[3]/div[1]/a/span[2]').text
origin=good.find_element_by_xpath('.//div[2]/div[3]/div[2]').text
4.接下來是處理二級頁面即goods裡面具體的内容,我做例子,隻擷取裡面的詳細資訊一欄的内容:
good.click()
driver.switch_to.window(driver.window_handles[-1])
js="window.scrollTo(0,1000)"
driver.execute_script(js)
time.sleep(1)
good是我擷取的商品,good.click()點選這個商品會跳轉到新的頁面,于是使用
driver.switch_to.window()
方法,這個方法是用來跳轉driver的,
driver.window_handles
這個是一個清單,這是一個存放所有的視窗的清單,剛打開一個視窗就會在這個清單裡面添加一個視窗元素,
driver.window_handles[-1]
這個就表示最後一個打開的視窗,最後一個sleep主要是為了輔助讓他加載完成
5.找到下一頁,模拟點選下一頁
try:
next_page = WebDriverWait(driver, 3, 0.2).until(lambda x: x.find_element_by_xpath('//span[contains(text(),"下一頁")]/..'))
except Exception as e:
print(e)
break
else:
next_page.click()
對于這段代碼做如下解釋:
WebDriverWait(driver, 3, 0.3).until(lambda x: x.find_element_by_xpath('//span[contains(text(),"下一頁")]/..'))
拆分解釋:
driver是驅動程式,3是最長等待時間,0.3也就是多久再去檢查是否存在,until就是具體找的内容,知道找到裡面的内容并且在3秒内,until裡面用的是一個匿名函數,其中的參數x值得就是哪個driver驅動程式,他要做的事情就是去找下一頁所在的标簽,
x.find_element_by_xpath('//span[contains(text(),"下一頁")]/..')
這個類似driver.find… 通過分析,他的下一頁按鈕在一個a标簽下包裹着,…表示他的上一級。
整段代碼的解釋:3秒内去等待加載一個’内容為“下一頁”的span标簽的父級标簽‘,每0.3秒檢查一下是否找到了,如果3秒内找到了則傳回結果(結果為一個标簽的對象),如果三秒都沒有找到則抛出異常,是以這裡要用try,except方法
對于我上面整體的代碼來說就是如果找到了下一頁則點選下一頁,如果沒找到則退出,這個退出就是說頁面中沒有下一頁,或者下一頁不可點選,其中對于下一頁不可點選我沒做判斷,我假定最後一頁沒有下一頁按鈕,則當找不到下一頁就說明是最後一頁就可以退出了。
總結:
對于這個例子來說,在操作的過程中總是遇到
StaleElementReferenceException
的異常,我的解決方案是在next_page.click()之後sleep兩秒,用于緩解他的加載,避免造成錯誤,但是這一定不是最好的辦法。暫時我就這樣做了。有更好的辦法我會更新部落格。
完整代碼如下:
import time
import urllib.parse
from selenium import webdriver
# option=webdriver.ChromeOptions()
# option.add_argument("headless")
# driver = webdriver.Chrome(options=option)
from selenium.webdriver.support.wait import WebDriverWait
driver=webdriver.Chrome()
kw="衣服"
url="https://s.taobao.com/search?q={kw}".format(kw=urllib.parse.quote(kw))
driver.get(url)
js="window.scrollTo(0,document.body.scrollHeight)"
driver.execute_script(js)
main_driver=driver.current_window_handle
while True:
time.sleep(2)
goods=driver.find_elements_by_xpath('//div[contains(@class,"J_MouserOnverReq")]')
for good in goods:
price=good.find_element_by_xpath('.//div[2]/div[1]/div/strong').text
title=good.find_element_by_xpath('.//div[2]/div[2]/a').text
shop_name=good.find_element_by_xpath('.//div[2]/div[3]/div[1]/a/span[2]').text
origin=good.find_element_by_xpath('.//div[2]/div[3]/div[2]').text
good.click()
driver.switch_to.window(driver.window_handles[-1])
js="window.scrollTo(0,1000)"
driver.execute_script(js)
time.sleep(1)
try:
tag_standard = WebDriverWait(driver, 5, 0.2).until(lambda x:x.find_element_by_xpath('//*[@id="J_TabBar"]/li[2]/a'))
except:
tag_standard=None
if tag_standard:
tag_standard.click()
try:
tag_table = driver.find_element_by_xpath('//table[@class="tm-tableAttr"]')
good_info = tag_table.text
except:
good_info=None
print(good_info)
driver.close()
driver.switch_to.window(main_driver)
try:
next_page = WebDriverWait(driver, 3, 0.2).until(lambda x: x.find_element_by_xpath('//span[contains(text(),"下一頁")]/..'))
except Exception as e:
print(e)
break
else:
next_page.click()
driver.quit()