爬蟲小專案(一)淘寶

小王子pp發表於2018-02-08

前幾天學習了selenium,於是動手寫了一個小爬蟲,主要通過利用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 bs4 import BeautifulSoup

下面介紹一下寫整個爬蟲的過程,程式碼我會根據自己的理解進行詳細的解析,當然如果我的理解錯了,希望各位能夠及時指出,畢竟我也只是初學者。

接下來按步驟來分解程式碼

第一步:進行初始化

所有的方法都是寫在類裡面的,因此我們第一步先初始化,要初始化的物件有兩個,一個是webdriver,一個是WebDriverWait。

那麼這兩個是什麼呢,一個是用來驅動瀏覽器的,一個是用來進行等待元素重新整理的。

(這裡提一下這個等待的過程。當我們開啟一個頁面的時候,假設頁面還沒有載入完成,這個時候可能會導致我們要定位的那個元素定位不到,從而報錯,而WebDriverWait,解決了這個問題,我們可以給它規定一個時間,在這個時間範圍內,我們會一直等待網頁載入並同時不斷的檢查我們想要定位的元素是否已經被載入出來了,如果是,那麼我們就繼續執行下面的程式碼,否則超過了最長時間時,丟擲異常。)

那麼接下來用來初始化的函式長下面這樣:

   def __init__(self):
        self.driver = webdriver.Chrome()               
        self.wait = WebDriverWait(self.driver,10) #self.driver是開啟的瀏覽器,10是最長等待時間

第二步:開啟淘寶網頁,自動輸入輸入我們想要查詢的商品

查詢的方法長這樣:

    def search(self,shop = None):                #商品名一開始為None,需要我們手動輸入
        print('開始搜尋了')
        self.driver.get('https://www.taobao.com')                  #開啟淘寶網首頁
        try:
            #判斷我們要的搜尋輸入框是否載入完成
            input = self.wait.until(                                         #返回的物件應該是所要尋找的目標元素
                EC.presence_of_element_located((By.CSS_SELECTOR,'#q'))        #presence_of_element_located這個函式接收的引數是元組,表示檢查某個元素是否在dom樹裡面,如果存在就返回這個元素
            )
            input.send_keys(u'{}'.format(shop))                             #如果要定位的元素被載入出來了,那麼執行下面的程式碼,這裡是將shop的值自動輸入搜尋框
            #判斷搜尋按鈕是否載入完成
            submit = self.wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_TSearchForm > div.search-button > button'))       #判斷某個按鈕是否可以點選,可以就返回這個按鈕
            )
            submit.click()                                                  #點選按鈕
        except TimeoutException:
            raise TimeoutException

我覺得還有一個地方需要說明一下,引數裡面的By.CSS_SELECTOR是CSS屬性選擇器,後面跟的是CSS屬性,該引數可以通過按F12,然後點選標籤所在位置然後右鍵選擇COPY,可以看到一個selector,點選複製然後貼上就可以了。

下面的也是一樣的道理

presence_of_element_located()接收的引數是一個元組,所以我們再裡面還要加多一個括號。

第三步:開始進行資訊的爬取

我在第二步輸入的是python,因此我要爬取的資訊有以下幾個:

1.圖片的連結 2.圖書的價格 3.付款的人數 4.圖書的名字 5.發貨地

這裡我們選擇BeautifulSoup來獲得這些資訊,bs4是解析網頁的神器,用的很爽。

那麼解析網頁的前提是我們要得到這個網頁的原始碼

怎麼做呢,用driver.page_source就可以啦,是不是很簡單。

所以爬取資訊的方法長這樣:

    def get_response(self):
        #判斷當前的商品載入出來沒有
        self.wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#mainsrp-itemlist .items .item'))    #整一頁的商品資訊在這個id為#mainsrp-itemlist .items .item的div裡面
        )
        html = self.driver.page_source               #獲取網頁的原始碼
        soup = BeautifulSoup(html,'html.parser')
        items = soup.find('div',class_ = 'm-itemlist').find_all('div',class_ = 'item')   #定位到單獨的商品上
        for item in items:         #這個迴圈用來獲取整個頁面每一個商品的五個資訊
            product = {
                'image':item.find('a').find('img')['src'],
                'price':item.find('div',class_ = ['price','g_price g_price-highlight']).find('strong').text,
                'num':item.find('div',class_ = 'deal-cnt').text[:-3],
                'name':item.find('div',class_ = 'row row-2 title').find('a').text.strip(),
                'location':item.find('div',class_ = 'location').text
            }
            print(product)   #迴圈列印每一個商品資訊

最後一步:翻頁

我們總不能只爬一頁吧,哈哈哈,那樣會感覺有點菜菜的。

在頁面的最下面有頁碼,然後還有一個框,裡面可以填你想跳轉的頁數,然後點旁邊的按鈕即可。

那麼我們首先要做的就是定位到這個框裡面,然後把裡面的數字頁碼清空,我們自己自動輸入一個進去,

然後再定位到旁邊的按鈕,點選確定,然後就可以跳轉到下一頁了。所以就很簡單的啦。

方法長這樣:

    def next_page(self,page):
        print(u'當前是第{}頁'.format(page))
        #檢查input標籤是否出現,出現的話進行後面的程式碼,這個標籤就是我們想要定位的那個可以輸入頁碼的框框
        input = self.wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > input'))
        )
        #用來清空頁碼
        input.clear()
        #element_to_be_clickable用來檢查按鈕是否可以被點選
        submit = self.wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit'))
        )
        input.send_keys(page)      #輸入頁碼值
        submit.click()              #點選確定,跳轉到下一頁
        #text_to_be_present_in_element用來確定某個文字是否包含在這個標籤裡面,這裡是為了確保翻到了第二頁,而且這裡如果檢查到了,也說明整個網頁載入完成了,因為這個頁數在網頁的最下面。
        self.wait.until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'),str(page))   #引數裡面的str(page)是當前頁的頁碼數,我們為了確定當前頁面是否是我們跳轉的頁面才這樣寫
        )
        tb.get_response()         #確定了跳轉到下一頁並載入完成後,進行下一次的資訊爬取

那麼方法的介紹就到這裡,下面貼上原始碼,寫的有點醜,希望各位多多見諒,這是我的第二個練手專案。以後還會不斷上傳新的練手專案。

原始碼如下:

# -*- coding:utf-8 -*-
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 bs4 import BeautifulSoup

class TB:
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver,10)
    def search(self,shop = None):
        print('開始搜尋了')
        self.driver.get('https://www.taobao.com')
        try:
            #判斷輸入框是否載入完成
            input = self.wait.until(                                         #返回的物件應該是所要尋找的目標元素
                EC.presence_of_element_located((By.CSS_SELECTOR,'#q'))        #presence_of_element_located這個函式接收的引數是元組,表示檢查某個元素是否在dom樹裡面,如果存在就返回這個元素,否則返回布林值。
            )
            input.send_keys(u'{}'.format(shop))                             #format格式化,將page傳入{}裡面
            #判斷按鈕是否載入完成
            submit = self.wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_TSearchForm > div.search-button > button'))       #判斷某個按鈕是否可以點選,可以就返回這個按鈕
            )
            submit.click()                                                  #點選按鈕
        except TimeoutException:
            raise TimeoutException
    def get_response(self):
        #判斷當前的商品載入出來沒有
        self.wait.until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#mainsrp-itemlist .items .item'))
        )
        html = self.driver.page_source
        soup = BeautifulSoup(html,'html.parser')
        items = soup.find('div',class_ = 'm-itemlist').find_all('div',class_ = 'item')
        for item in items:
            product = {
                'image':item.find('a').find('img')['src'],
                'price':item.find('div',class_ = ['price','g_price g_price-highlight']).find('strong').text,
                'num':item.find('div',class_ = 'deal-cnt').text[:-3],
                'name':item.find('div',class_ = 'row row-2 title').find('a').text.strip(),
                'location':item.find('div',class_ = 'location').text
            }
            print(product)
    def next_page(self,page):
        print(u'當前是第{}頁'.format(page))
        #檢查input標籤是否出現,出現的話進行後面的程式碼
        input = self.wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > input'))
        )
        #用來清空頁碼
        input.clear()
        #element_to_be_clickable用來檢查按鈕是否可以被點選
        submit = self.wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit'))
        )
        input.send_keys(page)
        submit.click()
        #text_to_be_present_in_element用來確定某個文字是否包含在這個標籤裡面,這裡是為了確保翻到了第二頁,而且這裡如果檢查到了,也說明整個網頁載入完成了,因為這個頁數在網頁的最下面。
        self.wait.until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'),str(page))
        )
        tb.get_response()

if __name__ == '__main__':
    tb = TB()
    shop = input('請輸入要搜尋的商品名字:\n')
    tb.search(shop)
    tb.get_response()
    for i in range(2,4):
        tb.next_page(i)

相關文章