python selenium 爬取《全國農產品商務信息公共服務平臺》

這是我參與的第二個項目,進程還是很順利的。這也不斷改進的過程,總共有三個版本:

  • 第一個版本是普通的爬取,對於某個農產品關鍵詞,獲取它全部的內容,後來由於我的網速太差,python運行報錯了,每個農產品都擁有八百多個頁面,如果重新開始,就會浪費很多時間,還不能確保它出錯,於是我就改進成了第二個版本;
  • 第二個版本是對某個農產品定頁爬取,爬取某個頁數區間的產品,用來彌補第一個版本信息出錯後,接着上次的頁數爬取數據
  • 第三個版本是全自動化爬取;在第二個的基礎上,瀏覽器的窗口總是彈出來干擾我做其他的事,所以就在這個版本中把瀏覽器隱藏起來,方便我工作。並且還加入隨機驗證碼,實現全部自動化。

網址: http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml

1、開始前工作:

1.1、分析網頁

可以把這個頁面簡單的理解成爲一個查詢接口,必須要輸入驗證碼,點擊搜索才能拿到數據,我經過簡單的分析後,並沒有找到數據的接口,所以就直接確定使用selenium來抓取數據了。
在這裏插入圖片描述

1.2、分析驗證碼

對於存在驗證碼的很多網頁,如果使用驗證碼的次數不多,我們就可以直接使用手動輸入,如果它不斷的有驗證碼,就需要讓它自動識別驗證碼了,但是我們爬取的這個網頁驗證碼並不多,每種產品就只需要輸入一次驗證碼,所以可以使用手動輸入,但是重點來了,該網頁經過我的測試,發現它的驗證碼並沒有實際的作業,也就是說這個驗證碼可以隨便輸入數字,也就爲我的第三個版本做鋪墊了!

1.3、分析URL

雖然說URL對selenium後期的爬取作用不大,但是這個的URL隱藏了大量的信息:
在這裏插入圖片描述

  • 默認時間只有三個月,如果需要查看更多商品的話,自己可以去更改時間
  • 在接下來的爬取中,它只是頁碼會有變化,其他的數據都不會改變
  • 注意:不能直接在URL上使用起始頁不爲1的其他頁數,因爲輸入驗證碼後都是數據都是從第一頁開始的
  • 建議用selenium時,不要讓URL攜帶驗證碼和頁數

2、第一個版本——普通的爬取

2.1、代碼彙總

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from lxml import etree
import time,xlwt

startTime =time.time()#記錄開始時間
all_page = []#用來保存所有頁面爬取到的數據
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
driver = webdriver.Chrome()
driver.implicitly_wait(5)
chrome_option = webdriver.ChromeOptions()
chrome_option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP
driver.get(url)#打開網頁網頁
driver.implicitly_wait(6)#等待加載六秒
time.sleep(10)

def next_page():
    for page in range(1,816,1):#從第1頁爬取到第815頁
        print ("~~~~~~~~~~正在爬取第%s頁,一共有815頁~~~~~~~~~"%page)
        if int(page) == 1:#當頁碼爲1時,不需要點擊下一頁,直接跳轉去獲取html源碼
            get_html()
        #點擊下一頁,下一頁的a標籤是最後一個標籤
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()
        
def get_html():
    driver.implicitly_wait(5)#等待加載,完成後自動執行下一步
    source = driver.page_source#獲取網頁源代碼
    html = etree.HTML(source)#lxml解析網頁
    spider(html)
        
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')#商品
            price = tr.xpath('./td[3]/span/text()')#價格
            unit = tr.xpath('./td[3]/text()')#單位
            market = tr.xpath('./td[4]/a/text()')#市場
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]   #詳情鏈接                     
            page = [time,goods,price,unit,market,link]#生成數組
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#創建工作簿
    sheet = book.add_sheet('生薑',cell_overwrite_ok=True)#創建表名,cell_overwrite_ok=True用於確認同一個cell單元是否可以重設值
    head = ['時間','產品','價格','單位','市場','鏈接']#定義表頭,即Excel中第一行標題
    for h in range(len(head)):
        sheet.write(0,h,head[h])#寫入表頭

    j = 1#第一行開始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,並寫入數據,重新設置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\農產品(生薑).xls')
    
if __name__ == '__main__':
    next_page()
    endTime =time.time()
    useTime =(endTime-startTime)/60
    print ("該次所獲的信息一共使用%s分鐘"%useTime)

2.2、運行代碼後手段點擊確定,並快速輸入驗證碼

在這裏插入圖片描述
現在的瀏覽器屬於被控制的狀態,但是它是支持認爲操作的。彈出瀏覽器後,該頁面會先有一個彈窗,只用點擊後才能輸入驗證碼,這裏的驗證碼可以隨便輸入四位數,如果怕手速不夠快的話,可以在代碼中多停一點時間,確保代碼正常運行!

2.3、報錯問題

如果你的環境運行這個代碼有誤,請檢查一下你的電腦是否配置了chromedriver.exe,因爲只是安裝selenium是不夠的,還需要配置瀏覽器的才行,如谷歌的需要下載對應版本的才行,沒有的話可以移步去看看:
python selenium新手入門安裝問題,這個方法可以不用配置環境,直接引用!

如果的pip配置過化境的話,簡單來說可以這樣做:

  1. http://npm.taobao.org/mirrors/chromedriver/下載對於自己瀏覽器的chromedriver.exe,我使用的是谷歌瀏覽器。
  2. 把你下載的chromedriver.exe複製到你安裝python的script路徑下,就算完成配置了。
  3. 有必要的話,可以重啓電腦加載環境變量。
    運行結果:
    在這裏插入圖片描述

3、第二個版本——定頁爬取

由於方法一在網不好的時候會導致請求失敗,不可能重新運行該代碼,最好的方式就是跟着上面的進程繼續往下走,所有必須從上面失敗的頁數開始爬取。

3.1、分析網頁

網頁上有快速跳轉到某個頁面的功能,所有可以利用這個方式進行定頁爬取數據,
在這裏插入圖片描述
操作步驟流程:

  1. 找到該輸入框的節點
  2. 輸入頁數
  3. 點擊確定
  4. 點擊下一頁

所以在我輸入的頁數就要先減一,回到前一頁,然後就可以調用一起的函數,點擊下一頁回到當前頁,獲取源代碼,繼續下一頁。。。

3.2、代碼彙總

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from lxml import etree
import time,xlwt

startTime =time.time()
all_page = []
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
driver = webdriver.Chrome()
driver.implicitly_wait(5)
chrome_option = webdriver.ChromeOptions()
chrome_option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP
driver.get(url)#打開網頁網頁
driver.implicitly_wait(6)#等待加載六秒
time.sleep(5)
gotopage = int(input("請輸入您開始的頁數:"))
gotopage = gotopage-1#減1的目的是前一頁,讓它點擊下一頁後才爬取
endpage = int(input("請輸入結束的頁數:"))

def choose_page():
    search = driver.find_element_by_xpath('//*[@id="gotopage"]')#定位輸入框節點
    search.clear()#清空搜索框
    search.send_keys(gotopage)#輸入關鍵詞
    driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/input[2]').click()#點擊確定
    next_page()

def next_page():
    for page in range(gotopage+1,endpage+1,1):
        print ("~~~~~~~~~~正在爬取第%s頁,一共有%s頁~~~~~~~~~"%(page,endpage))
        if int(page) == 1:
            get_html()
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()
        
def get_html():
    driver.implicitly_wait(5)
    source = driver.page_source#獲取源碼
    html = etree.HTML(source)
    spider(html)
        
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')
            price = tr.xpath('./td[3]/span/text()')
            unit = tr.xpath('./td[3]/text()')
            market = tr.xpath('./td[4]/a/text()')
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]                        
            page = [time,goods,price,unit,market,link]#生成數組
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#創建工作簿
    sheet = book.add_sheet('生薑',cell_overwrite_ok=True)#創建表名,cell_overwrite_ok=True用於確認同一個cell單元是否可以重設值
    head = ['時間','產品','價格','單位','市場','鏈接']#定義表頭,即Excel中第一行標題
    for h in range(len(head)):
        sheet.write(0,h,head[h])#寫入表頭

    j = 1#第一行開始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,並寫入數據,重新設置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\農產品(生薑).xls')
    
if __name__ == '__main__':
    choose_page()
    endTime =time.time()
    useTime =(endTime-startTime)/60
    driver.quit()#推出並關閉瀏覽器
    print ("該次所獲的信息一共使用%s分鐘"%useTime)

運行結果:
在這裏插入圖片描述

4、第三個版本——全自動化爬取

由於會彈出瀏覽器頁面,總是會影響我其他的操作,所以我要把瀏覽器關閉掉,代碼在運行的時候,我繼續做其他的事,這就面臨着這幾個問題:

4.1、全自動化三問題

4.1.1、自動點擊彈窗

selenium提供switch_to_alert方法:捕獲彈出對話框(可以定位alert、confirm、prompt對話框)

switch_to_alert() --定位彈出對話框
text() --獲取對話框文本值
accept() --相當於點擊“確認”
dismiss() --相當於點擊“取消”
send_keys() --輸入值(alert和confirm沒有輸入對話框,所以就不用能用了,只能使用在prompt裏)

1、alert窗口處理

# 獲取alert對話框
dig_alert = driver.switch_to.alert

# 打印警告對話框內容
print(dig_alert.text)

# alert對話框屬於警告對話框,我們這裏只能接受彈窗
dig_alert.accept()

2、confirm窗口處理

# 獲取confirm對話框
dig_confirm = driver.switch_to.alert

# 打印對話框的內容
print(dig_confirm.text)

# 點擊“確認”按鈕
dig_confirm.accept()

# 點擊“取消”按鈕
dig_confirm.dismiss()

3、prompt窗口處理

# 獲取prompt對話框
dig_prompt = driver.switch_to.alert

# 打印對話框內容
print(dig_prompt.text)

# 在彈框內輸入信息
dig_prompt.send_keys("Loading")

# 點擊“確認”按鈕,提交輸入的內容
dig_prompt.accept()

該網頁的彈窗正好符合第一種彈窗,只有確定按鈕!

4.1.2、自動輸入隨機驗證碼

  • 產生隨機4位數的驗證碼
import random
random.randrange(1000,9999,1)#1000<=隨機數<=9999,間隔爲1

4.1.3、退出瀏覽器

  • 由於把瀏覽器隱藏起來了,所以代碼運行完以後需要把瀏覽器關閉退出
driver.quit()#推出並關閉瀏覽器

4.2、代碼彙總

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from lxml import etree
import time,xlwt,random

startTime =time.time()#獲取開始時的時間
all_page = []
url = 'http://nc.mofcom.gov.cn/channel/jghq2017/price_list.shtml?par_craft_index=13075&craft_index=15641&par_p_index=&p_index=&startTime=2019-10-04&endTime=2020-01-02'
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')#上面三行代碼就是爲了將Chrome不彈出界面,實現無界面爬取
driver = webdriver.Chrome(chrome_options=chrome_options)

option = webdriver.ChromeOptions()
option.add_argument('--proxy--server=112.84.55.122:9999')#使用代理IP

driver.get(url)#打開網頁網頁
driver.implicitly_wait(6)#等待加載六秒

alert = driver.switch_to.alert #切換到alert
# print('alert text : ' + alert.text) #打印alert的文本
alert.accept() #點擊alert的【確認】按鈕

gotopage = int(input("請輸入您開始的頁數:"))
gotopage = gotopage-1#減1的目的是前一頁,讓它點擊下一頁後才爬取
endpage = int(input("請輸入結束的頁數:"))
randomNumber = random.randrange(1000,9999,1)#隨機生成一個四位數的驗證碼
def choose_page():
    #自動輸入驗證碼
    validity = driver.find_element_by_xpath('//*[@id="formJghqIndex"]/div/input[1]')
    validity.clear()#清空搜索框
    validity.send_keys(randomNumber)#輸入隨機驗證碼
    driver.find_element_by_xpath('//*[@id="formJghqIndex"]/div/input[2]').click()
    driver.implicitly_wait(3)#等待加載三秒
    #選擇起始頁
    search = driver.find_element_by_xpath('//*[@id="gotopage"]')#定位輸入框節點
    search.clear()#清空搜索框
    search.send_keys(gotopage)#輸入關鍵詞
    driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/input[2]').click()
    time.sleep(4)
    next_page()

#點擊下一頁
def next_page():
    for page in range(gotopage+1,endpage+1,1):
        print ("~~~~~~~~~~正在爬取第%s頁,一共有%s頁~~~~~~~~~"%(page,endpage))
        if int(page) == 1:#第一頁時直接獲取源代碼
            get_html()
        #點擊下一頁
        driver.find_element_by_xpath('/html/body/section/div/div[1]/div[4]/a[last()]').click()
        get_html()

#獲取網頁源碼並解析        
def get_html():
    driver.implicitly_wait(5)
    source = driver.page_source#獲取源代碼
    html = etree.HTML(source)#使用lxml解析網頁
    spider(html)

#提取信息
def spider(html):
    for tr in html.xpath('/html/body/section/div/div[1]/table/tbody/tr'):
        time = tr.xpath('./td[1]/text()')
        if len(time) != 0:
            goods = tr.xpath('./td[2]/span/text()')
            price = tr.xpath('./td[3]/span/text()')
            unit = tr.xpath('./td[3]/text()')
            market = tr.xpath('./td[4]/a/text()')
            link = 'http://nc.mofcom.gov.cn/'+tr.xpath('./td[4]/a/@href')[0]                        
            page = [time,goods,price,unit,market,link]#生成數組
            all_page.append(page)
            saveData()
def saveData():
    book = xlwt.Workbook(encoding = 'utf-8')#創建工作簿
    sheet = book.add_sheet('生薑',cell_overwrite_ok=True)#創建表名,cell_overwrite_ok=True用於確認同一個cell單元是否可以重設值
    head = ['時間','產品','價格','單位','市場','鏈接']#定義表頭,即Excel中第一行標題
    for h in range(len(head)):
        sheet.write(0,h,head[h])#寫入表頭

    j = 1#第一行開始
    for list in all_page:
        k = 0
        for date in list:
            sheet.write(j,k,date)#迭代列,並寫入數據,重新設置,需要cell_overwrite_ok=True
            k = k+1
        j = j+1
    book.save('D:\\農產品(生薑).xls')
    
if __name__ == '__main__':
    choose_page()
    endTime =time.time()#獲取結束時的時間
    useTime =(endTime-startTime)/60
    driver.quit()#推出並關閉瀏覽器
    print ("該次所獲的信息一共使用%s分鐘"%useTime)

編輯器運行結果:
在這裏插入圖片描述
Excel結果截屏:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章