天天看點

python3下用selenium庫和chrome的headless模式實作網頁抓取(注釋中有用phantomJS的小段代碼)

代碼功能:實作動态網頁下的資料抓取(本例主要是因為要點選“加載更多”的按鈕的原因)

要注意的地方:

1、chrome無需專門下載下傳什麼headless版本,桌面版在用的就可以,但是要下多一個chromedriver,并且要跟所用的chrome版本對應,chromedriver下載下傳位址為:http://chromedriver.storage.googleapis.com/index.html。

2、需要添加chrome.exe所在檔案夾位址進系統環境變量,具體可檢視網上教程。不複雜。

3、selenium.webdriver.ChromeOptions下的add_argument和binary_location要設定好,才能正确打開。

4、記得要關閉系統浏覽器和驅動程序,才能釋放系統資源。此處close方法不行,要用quit方法。

好,下面二話不說,貼上代碼:

# 運作于python3版本
# 這是一個目的為在“https://www.cjrl.cn/jiedu/meiguo-325.html”該網址爬取EIA資料和API資料的程式
# EIA[美國能源資訊署(Energy Information Administration)]原油庫存資料:
# API[美國石油協會(American Petroleum Institute)]庫存資料:
# 改為用chrome的headless版本(預計會更快)
#-*- coding:utf-8 -*-

# ***************************************************************************
# 導入子產品
import re
import os
import chardet
import codecs
import traceback
import time
import csv
from urllib.request import urlopen as uo
from urllib.request import urlretrieve as ur
from selenium import webdriver
# 導入所需子產品結束
# ***************************************************************************

# ***************************************************************************
# 基礎資料
eia_page_link = 'https://www.cjrl.cn/jiedu/meiguo-325.html'
api_page_link = 'https://www.cjrl.cn/jiedu/meiguo-324.html'
# 基礎資料指派完畢
# ***************************************************************************

# ***************************************************************************
# 定義功能函數
# ***************************************
# 函數一:mkdir() 建立目錄
def mkdir(cur_dir, data_type, date_span):
    if data_type != 'eia' and data_type != 'api':
        print('資料源名出錯!!!')
    # 去除首位空格
    path = cur_dir
    path = path.strip()
    # 去除尾部符号 ‘\\’
    path = path.rstrip('\\')
    # 分eia或api不同資料分檔案夾存儲
    path = path + '\\' + data_type
    # 判斷路徑是否存在
    isExists = os.path.exists(path)
    # 去掉目錄路徑,傳回檔案夾名
    fp_new = os.path.basename(path)
    if not isExists:
        # 如果不存在,則建立目錄 os.makedirs(path)
        os.makedirs(path)
        print('新檔案夾:  ' + fp_new + ' 建立成功')
    else:
        # 如果目錄存在則不建立
        print('檔案夾:  ' + fp_new + ' 已存在')
    mkfile_dir = path + '\\' + data_type + '_' +date_span
    return mkfile_dir
# 函數一定義完畢
# ***************************************

# ***************************************
# 函數二:mkfile() 建立檔案
def mkfile(mkfile_dir):
    f_name = os.path.basename(mkfile_dir)  # 分割出檔案名
    isexist = os.path.exists(mkfile_dir+'.csv')  # 判斷路徑下的檔案是否存在
    if not isexist:
        with codecs.open(mkfile_dir + '.csv', 'w') as f:
            print('新csv檔案: ' + f_name + '.csv  已建立完成')
    else:
        print('csv檔案:  ' + f_name + '.csv  已存在\n  請及時關閉相關資料檔案,否則将出錯!')
        check = input('是否已關閉檔案?輸入Y/N:')
        if check == 'Y' or check == 'y':
            return()
        else:
            print('請關閉檔案後再次運作該程式!')
            exit(0)
# 函數二定義完畢
# ***************************************
# 定義功能函數完畢
# ***************************************************************************


# ***************************************************************************
# 主程式開始
cur_dir = os.getcwd()
data_type, date_span = \
    map(str, input('''請輸入要擷取eia或api,同時以'200701-200701'格式輸入擷取時間段:(空格隔開)''').split())
# 按不同資料生成資料檔案夾,并傳回csv資料檔案名絕對路徑
mkfile_dir = mkdir(cur_dir, data_type, date_span)
# 按傳回的csv資料檔案絕對路徑生成檔案
mkfile(mkfile_dir)

if data_type == 'eia':
    url_source = eia_page_link
if data_type == 'api':
    url_source = api_page_link

# webdriver中的PhantomJS方法可以打開一個我們下載下傳的靜默浏覽器(headless version)。
# 輸入executable_path為目前檔案夾下的phantomjs.exe以啟動浏覽器,生成浏覽器句柄
# driver = webdriver.PhantomJS(executable_path="phantomjs.exe")

# # **************** version 1 of using chrome(not valid) *************************
# option = webdriver.ChromeOptions()
# option.add_argument('headless')
# driver = webdriver.Chrome(executable_path='chromedriver.exe',chrome_options=option)
# # *******************************************************************************

# **************** version 2 of using chrome(valid) *************************
option = webdriver.ChromeOptions()
option.add_argument('--headless')
option.binary_location = r'C:\Users\SYSUZZD\AppData\Local\Google\Chrome\Application\chrome.exe'
driver = webdriver.Chrome(chrome_options=option)
# *******************************************************************************

# 使用浏覽器請求資料頁面
print('正在加載網頁中的 %s資料' % data_type.upper())
driver.get(url_source)

# 根據所需時間區間起始月份進入多次點選循環
click_flag = True
click_count = 1
inquiry_from_date = date_span[0:6]
str_inquiry_from_date_year = inquiry_from_date[0:4]
inquiry_from_date_year = int(str_inquiry_from_date_year)
str_inquiry_from_date_month = inquiry_from_date[4:6]
inquiry_from_date_month = int(str_inquiry_from_date_month)
inquiry_to_date = date_span[7:13]
str_inquiry_to_date_year = inquiry_to_date[0:4]
inquiry_to_date_year = int(str_inquiry_to_date_year)
str_inquiry_to_date_month = inquiry_to_date[4:6]
inquiry_to_date_month = int(str_inquiry_to_date_month)

while click_flag:
    # 利用find_element_by_xpath該定位方法定位到加載更多資料的标簽上
    contents = driver.find_element_by_xpath("//div[@id='loadmore']/a")

    # 利用find_element_by_id 和.text方法找到'datadetail'為id的标簽子產品中的資料
    data = driver.find_element_by_id('datadetail').text
    # 把日期後邊的逗号去掉
    data = data.replace(r',', '')
    # 按行分割data字元串
    temp = data.split('\n')
    # 判斷目前資料起始時間是否滿足查詢時段起始要求
    data_from_date = temp[len(temp) - 1][0:10]  # 2018-03-28
    data_to_date = temp[1][0:10]
    data_from_date_year = int(data_from_date[0:4])
    data_from_date_month = int(data_from_date[5:7])
    data_from_date_day = int(data_from_date[8:10])

    if data_from_date_year < inquiry_from_date_year:
        break
    elif data_from_date_year == inquiry_from_date_year:
        if data_from_date_month < inquiry_from_date_month:
            break
        elif data_from_date_month == inquiry_from_date_month:
            if data_from_date_day - 7 <= 0:
                break

    # 浏覽器模拟點選
    contents.click()
    # 提示第幾次點選
    print('''已第%d次點選'加載更多'按鈕''' % click_count)
    click_count += 1
    # 等待1s使資料重新整理
    time.sleep(1)

# 關閉浏覽器
# driver.close()   # 用close方法并不能使driver和chrome程序退出
driver.quit()    # 實測quit方法可以讓driver和chrome程序退出

# 對所需時間段計算temp對應的起止索引值
str_inquiry_from_year_month = str_inquiry_from_date_year + '-' + str_inquiry_from_date_month
str_inquiry_to_year_month = str_inquiry_to_date_year + '-' + str_inquiry_to_date_month
index = 0
flag1 = 0
flag2 = 0
for tempi in temp:
    if flag1 ==0 and str_inquiry_to_year_month in tempi:
        index_start = index
        flag1 = 1
    if str_inquiry_from_year_month in tempi:
        index_to = index
        flag2 = 1
    if flag2 == 1:
        if not str_inquiry_from_year_month in tempi:
            break
    index += 1

temp[0] = '公布日期 公布時間 前值 預測值 公布值 影響美元 影響金銀石油'
with open(mkfile_dir+'.csv', 'w') as f:
    print('正在往  %s 中寫入資料' % (mkfile_dir + '.csv'))
    tempk = temp[0].replace(r' ', r',')
    f.writelines(tempk + '\n')
    for tempi in temp[index_start:index_to + 1]: #記得終止索引值應該+1
        tempk = tempi.replace(r' ', r',')    #将資料中的' '(空格) 改為 ',',友善作為csv分割符
        tempj = tempk.replace(r'---', '0')   #将資料中的'---' 改為 '0'
        f.writelines(tempj+'\n')
    print('寫入資料完成!')

# print('退出PhantomJS')
# driver.quit()


# ***************************************************************************
           

繼續閱讀