【Selenium框架2】Selenium框架爬取淘寶商品信息

特別聲明:

  1. 供交流學習使用,不得用作商業用途。
  2. 如有違規侵權,請聯系刪除。

一、Selenium框架介紹

Selenium 是一個用于瀏覽器自動化測試的框架,可以用來爬取任何網頁上看到的數據。
簡單地說,就是模擬一個人所有的網頁操作的行為

Selenium的下載與安裝:

  • 安裝:在終端輸入 pip install selenium
  • 下載:下載Chromedriver,解壓后放在…\Google\Chrome\Application\(右擊Chrome圖標,打開文件所在文件夾)
  • 環境變量:將該目錄添加至環境變量:右鍵點擊我的電腦----->屬性--->高級系統設置---->環境變量------>在path路徑下添加上文中…\Google\Chrome\Application\路徑

使用代碼測試:
Selenium的簡單使用:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')

elem = driver.find_element_by_xpath('//*[@id = "kw"]')  #查找輸入框
elem.send_keys('Python Selenium',Keys.ENTER)  #模擬點擊回車
print(driver.page_source)
模擬百度搜索
  • 遇到的問題:報錯顯示缺少參數"Python3 Selenium自動化測試賦值出現:WebDriverException: Message: unknown error: call function result missing 'value'",發現的Chromedriver版本要跟當前Chrome版本一致才可以

Chrome版本對應Chromedriver下載地址

Selenium的優缺點:

  • 優點:Selenium可以爬取任何網頁的任何內容,因為它是通過瀏覽器訪問的方式進行數據的爬取,沒有網站會拒絕瀏覽器的訪問。 但是淘寶和知乎會對Selenium有反爬機制,需要進行偽裝。
  • 缺點:時間以及內存消耗太大,可以開啟無頭模式headless或者PhantomJS webdriver緩解這個問題

二、Selenium的使用

跟人操作網頁一樣,都是需要查找和操作網頁元素

查找元素

XXX表示用CSS、id、name、identifier、XPath定位、 超鏈接、DOM、 CSS selector進行定位。更多定位方式
PS: 對于網頁的定位路徑,只需要在谷歌瀏覽器中,鼠標放到對應元素--右鍵--檢查--在右邊的網頁源碼相應位置--右鍵--復制--選擇相應的路徑定位方法

  • 1.直接用webdriver對象的查找
driver.find_element_by_XXX() 
查找符合條件的單個元素 
driver.find_elements_by_XXX() 
查找符合條件的一組元素

此方法通常需要前面編寫time.sleep()一定秒數,讓網頁加載完畢,否則可能會找不到元素

    1. WebDriverWait對象(更推薦)
      此方法可以顯式等待網頁加載
      顯式等待可以自定義等待的條件,用于更加復雜的頁面等待條件
from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get('填入網站的url')
wait = WebDriverWait(driver, 10)  構建WebDriverWait對象,10秒加載時間
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'CSS選擇器定位路徑')))  # 很多有經驗的selenium用戶推薦CSS定位方式,因為它比XPath更快。而且可以在HTML文件中找到更復雜的對象。
    1. 使用pyquery庫
      類似JQuery
      定位元素
      此方法適合用作返回網頁元素進行下一步處理
from selenium import webdriver
from pyquery import PyQuery as pq


driver = webdriver.Chrome()
driver.get('填入網站的url')
html = driver.page_source()
doc = pq(html)
#pyquery(browser.page_source)就相當于requests.get獲取的內容
items = doc('CSS選擇器路徑').items()

操作元素

相應的,我們有:

    1. 直接用webdriver對象的操作
from selenium import webdriver

account = browser.find_element_by_xpath('//*[@id="TPL_username_1"]')
account.clear()
account.send_keys("用戶名")
passwd = browser.find_element_by_xpath('//*[@id="TPL_password_1"]')
passwd.send_keys("密碼")
submit = browser.find_element_by_xpath('//*[@id="J_SubmitStatic"]')
submit.click()  #點擊登錄按鈕
    1. WebDriverWait對象的操作(更推薦)
      也是可以顯示等待加載時間
from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 

input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')))
submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')))
input.clear()  # 清除輸入框內容
input.send_keys(page_num)  # 輸入輸入框內容
submit.click()      # 點擊確定按鈕

三、Selenium項目實戰(爬取淘寶商品)

思路:


爬取淘寶思路
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Use for get infomation from taobao by ChromeDriver
# Author:Robin; Created in 20190831
from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 
from selenium.common.exceptions import TimeoutException  #檢查網絡請求是否超時
#from selenium.webdriver import ChromeOptions
#from selenium.webdriver.common.keys import Keys
#from selenium.webdriver import ActionChains
from pyquery import PyQuery as pq 
from pymongo import MongoClient
#import random
import time
import re

browser = webdriver.Chrome()  #創建webdriver對象
wait = WebDriverWait(browser, 10) 

#進入淘寶網,輸入商品名稱,返回頁面
def search(good):
    try:
        browser.get('https://www.taobao.com/')
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#q')))  # 搜索輸入框
        submit = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button')))  # 搜索點擊按
        keys = '{}'.format(good)
        input.send_keys(keys) #輸入商品名
        submit.click()      #點擊搜索
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total')))
        get_products(good)
        return total.text   #總頁數
    except TimeoutException:
        #login(browser)
        search(good)
        
#跳轉到下一頁
def next_page(page_num, good):
    print('正在爬取第{}頁'.format(page_num))
    try:
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')))     #頁碼輸入框
        submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')))   #頁碼跳轉確定按鈕
        input.clear()   #清空頁碼框
        input.send_keys(page_num)   #輸入頁碼
        submit.click()   # 點擊確定
        time.sleep(10)  #防止爬取過快
        wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_num)))  #檢查是否跳轉到正確頁數
        get_products(good)
    except TimeoutException:
        next_page(page_num, good)
#得到淘寶商品信息
def get_products(good):
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
    html = browser.page_source
    doc = pq(html)  # pyquery(browser.page_source)就相當于requests.get獲取的內容, 構建PyQuery對象
    items = doc('#mainsrp-itemlist .items .item').items()    #獲取所有的‘#mainsrp-itemlist .items .item’選擇出來的內容下的各項
    for item in items:   # 每個item變量都是一個PyQuery對象,然后再調用它的find()方法,傳入CSS選擇器,就可以獲取單個商品的特定內容了。
        products = {
            'image': item.find('.pic .img').attr('src'),    #獲取圖片鏈接
            'price': item.find('.price').text(),
            'deal': item.find('.deal-cnt').text()[:-3],
            'title': item.find('.title').text(),
            'shop': item.find('.shop').text(),
            'location': item.find('.location').text(),
        }
        #print(products)
        save_to_mongo(products, good)
# 保存數據到MongoDB
def save_to_mongo(result, good):
    client = MongoClient('mongodb://localhost:27017')
    db = client.taobao
    set_name = '{}'.format(good)
    goods_set = db[set_name]   # 創建以商品名命名的數據集
    try:
        if goods_set.insert(result):  # 插入到MongoDB數據庫相應數據集
            print("存儲到MONGODB成功",result)
    except Exception:
        print("存儲到MONGODB失敗",result)

def main(good):
    print('正在爬取第1頁...')
    total = search(good)
    total = int(re.compile('(\d+)').search(total).group(1))
    for i in range(2, total+1):
        next_page(i, good)
    browser.close() #把瀏覽器關掉


if __name__ == '__main__':
    main('樹莓派')

運行結果:

運行結果

數據庫展示

問題

  1. 淘寶模擬登錄:
  • 一開始我以為淘寶點擊搜索商品是都會自動跳轉到登錄頁面的,然后就想用Selenium模擬人的登錄,然后再利用selenium.webdriver的ActionChains的click_and_hold(slider).perform()click_and_hold(slider).perform() 方法,模擬人操作時候先快后慢的特點
  • 后面才發現淘寶識別的是瀏覽器發送的一些參數判定是Selenium還是普通瀏覽器
  • 但是感覺這個代碼挺有意思的,或許以后也有用,也拿出來分享下
from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 
from selenium.common.exceptions import TimeoutException  #檢查網絡請求是否超時
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from pyquery import PyQuery as pq 
from pymongo import MongoClient
import random
import time
import re

##選用開發者模式,創建一個瀏覽器對象,可避免被淘寶檢測到是selenium模擬瀏覽器
option = ChromeOptions()
option.add_argument('--proxy-serve=127.0.0.1:8080')
option.add_experimental_option('excludeSwitches',['enable-automation']) 
#chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])#禁止打印日志 跟上面只能選一個
browser = webdriver.Chrome(options=option)
browser = webdriver.Chrome()
wait = WebDriverWait(browser, 10)

# 滑塊移動軌跡計算:使得滑塊先快后慢
def get_track(distance):
    track = []
    current = 0
    mid = distance * (1/2)
    t = 2
    v = 0
    a = 4
    a1 = -4
    while current < distance:
        #滑條前1/2的部分加速滑動
        if current < mid:
            move = v * t + 1/2 * a *t * t   #物理上勻加速運動計算某一時間內的位移: s = v*t + (1/2)a*t^2
            current += move                 
            track.append(round(move))
            v = v + a*t                     # 加速運動物體某一時刻的瞬時速度         
        else:
            #滑條后1/2的部分加速度減慢
            move = v * t + 1/2 * a1 *t *t
            current += move
            track.append(round(move))
            v = v + a1*t

    return track

def drag(length, xpath):
    if browser.find_element_by_xpath("{}".format(xpath)):
        slider = browser.find_element_by_xpath("{}".format(xpath))   #找到滑動按鈕  
        track = get_track(length)  #模擬運動軌跡,速度先快后慢
        ActionChains(browser).click_and_hold(slider).perform()          # 按住滑塊滑動
        for x in track: 
            ActionChains(browser).drag_and_drop_by_offset(slider, xoffset=x, yoffset=random.randint(1,3)).perform()
        ActionChains(browser).release().perform()
    else:
        pass
    
# Selenium控制的情況下搜索商品,淘寶會自動跳轉到登錄界面
def login(browser):
    try:
        button = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_Quick2Static')))
        button.click()
        account = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#TPL_username_1')))
        passwd = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#TPL_password_1')))
        submit = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_SubmitStatic')))
        account.clear()
        account.send_keys('用戶名')
        passwd.send_keys('密碼')
        submit.click()

        try:
            change_login = browser.find_element_by_id('J_Quick2Static')   #點擊密碼登錄按鈕,選擇用密碼方式登錄
            time.sleep(3)
            change_login.click()     
        except  Exception:
            pass

        time.sleep(3)
        account = browser.find_element_by_xpath('//*[@id="TPL_username_1"]')
        account.clear()
        account.send_keys('用戶名’)
        passwd = browser.find_element_by_xpath('//*[@id="TPL_password_1"]')
        passwd.send_keys('密碼')
        
        try:
            drag(700, "http://*[@id='nc_1_n1z']")
        except Exception:
            pass

        submit = browser.find_element_by_xpath('//*[@id="J_SubmitStatic"]')
        submit.click()  #點擊登錄按鈕

        try:
            index_page = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '//*[@id="J_SiteNavHome"]/div/a/span')))
            index_page.click()
        except  Exception:
            login(browser)

    except TimeoutException:
        login(browser)

if __name__ == '__main__':
    login(browser)
  1. 有時候用正則表達式匹配淘寶的頁碼,total = int(re.compile('(\d+)').search(total).group(1))會匹配失敗,不知道究竟是加載不完全還是淘寶的一些反爬措施,有空再研究下
  2. 當爬取到一定頁數的時候,淘寶會檢查到頁面的異常,然后就會卡在驗證頁面,出現手動也無法通過驗證的情況,所以應該要多準備幾個代理和IP,使用scrapy框架來爬取會更加方便。

改進

  1. 由于淘寶對Selenium的反爬做得比較好,所以登錄需要手動掃碼登錄,如果需要模擬登錄請參考以下鏈接:
  1. 如果需要更新MongoDB數據庫,請參考:

更多Selenium技巧擴展閱讀:

可以用于掩飾Selenium,防止被識別出
設置headless和關閉圖片緩存,可以減少機器負荷,提高性能
- chrome配置
設置無頭瀏覽器PhantomJS和關閉圖片緩存
- Windows下PhantomJS的安裝和使用
- Python3網絡爬蟲開發實戰 1.2.5-PhantomJS的安裝
- Python爬蟲利器四之PhantomJS的用法
Selenium更多定位用法:
- 菜鳥學自動化測試(五)-----selenium命令之定位頁面元素
更多CSS選擇器用法:(PS:這又是一個大坑)
- 【Selenium專題】元素定位之CssSelector
- Selectors Level 3官方文檔
其他參考教程:
- 網絡爬蟲(python項目)
- 爬蟲實踐---Selenium-抓取淘寶搜索商品信息
- (九)使用Selenium+Chrome/PhantomJS(模擬瀏覽器)抓取淘寶商品美食信息|Python3網絡爬蟲開發實戰

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375