天天看點

使用selenium爬取淘寶頁面中的商品資訊

一、分析

淘寶頁面中的商品都是用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()