新聞中心
單進(jìn)程+selenium模擬怎么爬取領(lǐng)導(dǎo)留言并整合成CSV文件,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、網(wǎng)頁(yè)空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、臨漳網(wǎng)站維護(hù)、網(wǎng)站推廣。
項(xiàng)目概述
1.項(xiàng)目說(shuō)明
主要是對(duì)領(lǐng)導(dǎo)留言板內(nèi)的所有留言的具體內(nèi)容進(jìn)行抓取,對(duì)留言詳情、回復(fù)詳情和評(píng)價(jià)詳情進(jìn)行提取保存,并用于之后的數(shù)據(jù)分析和進(jìn)一步處理,可以對(duì)政府的決策和電子政務(wù)的實(shí)施提供依據(jù)。
對(duì)于圖中標(biāo)出的數(shù)據(jù),均要進(jìn)行爬取,以此構(gòu)成一條留言的組成部分。
2.環(huán)境配置
(1)Python:3.x
(2)所需庫(kù):
dateutil安裝方法:
pip install python-dateutil
selenium安裝方法:
pip install selenium
(3)模擬驅(qū)動(dòng):chromedriver,可點(diǎn)擊https://download.csdn.net/download/CUFEECR/12193208進(jìn)行下載Google瀏覽器80.0.3987.16版對(duì)應(yīng)版本,或點(diǎn)擊http://chromedriver.storage.googleapis.com/index.html下載與Google對(duì)應(yīng)版本,并放入Python對(duì)應(yīng)安裝路徑下的Scripts目錄下。
二、項(xiàng)目實(shí)施
1.導(dǎo)入所需要的庫(kù)
import csv import os import random import re import time import dateutil.parser as dparser from random import choice from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.chrome.options import Options
主要導(dǎo)入在爬取過(guò)程中需要用到的處理庫(kù)和selenium中要用到的類。
2.全局變量和參數(shù)配置
## 時(shí)間節(jié)點(diǎn) start_date = dparser.parse('2019-06-01') ## 瀏覽器設(shè)置選項(xiàng) chrome_options = Options() chrome_options.add_argument('blink-settings=imagesEnabled=false')
我們假設(shè)只爬取2019.6.1以后的留言,因?yàn)檫@之前的留言自動(dòng)給好評(píng),沒(méi)有參考價(jià)值,因此設(shè)置時(shí)間節(jié)點(diǎn),并禁止網(wǎng)頁(yè)加載圖片,減少對(duì)網(wǎng)絡(luò)的帶寬要求、提升加載速率。
3.產(chǎn)生隨機(jī)時(shí)間和用戶代理
def get_time(): '''獲取隨機(jī)時(shí)間''' return round(random.uniform(3, 6), 1) def get_user_agent(): '''獲取隨機(jī)用戶代理''' user_agents = [ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", "Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20", "Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko) Version/5.1 Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" ] ## 在user_agent列表中隨機(jī)產(chǎn)生一個(gè)代理,作為模擬的瀏覽器 user_agent = choice(user_agents) return user_agent
產(chǎn)生隨機(jī)時(shí)間并隨機(jī)模擬瀏覽器用于訪問(wèn)網(wǎng)頁(yè),降低被服務(wù)器識(shí)別出是爬蟲(chóng)而被禁的可能。
4.獲取領(lǐng)導(dǎo)的fid
def get_fid(): '''獲取所有領(lǐng)導(dǎo)id''' with open('url_fid.txt', 'r') as f: content = f.read() fids = content.split() return fids
每個(gè)領(lǐng)導(dǎo)都有一個(gè)fid用于區(qū)分,這里采用手動(dòng)獲取fid并保存到txt中,在開(kāi)始爬取時(shí)再逐行讀取。
5.獲取領(lǐng)導(dǎo)所有留言鏈接
def get_detail_urls(position, list_url): '''獲取每個(gè)領(lǐng)導(dǎo)的所有留言鏈接''' user_agent = get_user_agent() chrome_options.add_argument('user-agent=%s' % user_agent) drivertemp = webdriver.Chrome(options=chrome_options) drivertemp.maximize_window() drivertemp.get(list_url) time.sleep(2) ## 循環(huán)加載頁(yè)面 while True: datestr = WebDriverWait(drivertemp, 10).until( lambda driver: driver.find_element_by_xpath( '//*[@id="list_content"]/li[position()=last()]/h4/span')).text.strip() datestr = re.search(r'\d{4}-\d{2}-\d{2}', datestr).group() date = dparser.parse(datestr, fuzzy=True) print('正在爬取鏈接 --', position, '--', date) if date < start_date: break ## 模擬點(diǎn)擊加載 try: WebDriverWait(drivertemp, 50, 2).until(EC.element_to_be_clickable((By.ID, "show_more"))) drivertemp.execute_script('window.scrollTo(document.body.scrollHeight, document.body.scrollHeight - 600)') time.sleep(get_time()) drivertemp.execute_script('window.scrollTo(document.body.scrollHeight - 600, document.body.scrollHeight)') WebDriverWait(drivertemp, 50, 2).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="show_more"]'))) drivertemp.find_element_by_xpath('//*[@id="show_more"]').click() except: break time.sleep(get_time() - 1) detail_elements = drivertemp.find_elements_by_xpath('//*[@id="list_content"]/li/h3/b/a') ## 獲取所有鏈接 for element in detail_elements: detail_url = element.get_attribute('href') yield detail_url drivertemp.quit()
根據(jù)第4步提供的fid找到一個(gè)領(lǐng)導(dǎo)對(duì)應(yīng)的所有留言的鏈接,由于領(lǐng)導(dǎo)的留言列表并未一次顯示完,下方有一個(gè)加載更多按鈕,如下
每次需要進(jìn)行點(diǎn)擊向下加載,所以要模擬點(diǎn)擊的操作,向下滑動(dòng),等完全加載后再次點(diǎn)擊,直到底部。函數(shù)返回值時(shí),不是一次返回一個(gè)列表,而是通過(guò)yield關(guān)鍵字生成生成器,按照程序執(zhí)行的進(jìn)度生成url,可以減少內(nèi)存的壓力。
6.獲取留言詳情
def get_message_detail(driver, detail_url, writer, position): '''獲取留言詳情''' print('正在爬取留言 --', position, '--', detail_url) driver.get(detail_url) ## 判斷,如果沒(méi)有評(píng)論則跳過(guò) try: satis_degree = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_class_name("sec-score_firstspan")).text.strip() except: return ## 獲取留言各部分內(nèi)容 message_date_temp = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[6]/h4/span")).text message_date = re.search(r'\d{4}-\d{2}-\d{2}', message_date_temp).group() message_datetime = dparser.parse(message_date, fuzzy=True) if message_datetime < start_date: return message_title = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_class_name("context-title-text")).text.strip() label_elements = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_elements_by_class_name("domainType")) try: label1 = label_elements[0].text.strip() label2 = label_elements[1].text.strip() except: label1 = '' label2 = label_elements[0].text.strip() message_content = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[6]/p")).text.strip() replier = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/h4[1]/i")).text.strip() reply_content = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/p")).text.strip() reply_date_temp = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/h4[2]/em")).text reply_date = re.search(r'\d{4}-\d{2}-\d{2}', reply_date_temp).group() review_scores = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_elements_by_xpath("/html/body/div[8]/ul/li[2]/h5[1]/span/span/span")) resolve_degree = review_scores[0].text.strip()[:-1] handle_atti = review_scores[1].text.strip()[:-1] handle_speed = review_scores[2].text.strip()[:-1] review_content = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[2]/p")).text.strip() is_auto_review = '是' if (('自動(dòng)默認(rèn)好評(píng)' in review_content) or ('默認(rèn)評(píng)價(jià)' in review_content)) else '否' review_date_temp = WebDriverWait(driver, 2.5).until( lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[2]/h5[2]/em")).text review_date = re.search(r'\d{4}-\d{2}-\d{2}', review_date_temp).group() ## 存入CSV文件 writer.writerow( [position, message_title, label1, label2, message_date, message_content, replier, reply_content, reply_date, satis_degree, resolve_degree, handle_atti, handle_speed, is_auto_review, review_content, review_date])
我們只需要有評(píng)論的留言,因此在最開(kāi)始要過(guò)濾掉沒(méi)有評(píng)論的留言。然后通過(guò)xpath、class_name等方式定位到相應(yīng)的元素獲取留言的各個(gè)部分的內(nèi)容,每條留言共保存14個(gè)內(nèi)容,并保存到csv中。
7.獲取并保存領(lǐng)導(dǎo)所有留言
def get_officer_messages(index, fid): '''獲取并保存領(lǐng)導(dǎo)的所有留言''' user_agent = get_user_agent() chrome_options.add_argument('user-agent=%s' % user_agent) driver = webdriver.Chrome(options=chrome_options) list_url = "http://liuyan.people.com.cn/threads/list?fid={}##state=4".format(fid) driver.get(list_url) position = WebDriverWait(driver, 10).until( lambda driver: driver.find_element_by_xpath("/html/body/div[4]/i")).text ## time.sleep(get_time()) print(index, '-- 正在爬取 --', position) start_time = time.time() ## encoding='gb18030' csv_name = position + '.csv' ## 文件存在則刪除重新創(chuàng)建 if os.path.exists(csv_name): os.remove(csv_name) with open(csv_name, 'a+', newline='', encoding='gb18030') as f: writer = csv.writer(f, dialect="excel") writer.writerow( ['職位姓名', '留言標(biāo)題', '留言標(biāo)簽1', '留言標(biāo)簽2', '留言日期', '留言內(nèi)容', '回復(fù)人', '回復(fù)內(nèi)容', '回復(fù)日期', '滿意程度', '解決程度分', '辦理態(tài)度分', '辦理速度分', '是否自動(dòng)好評(píng)', '評(píng)價(jià)內(nèi)容', '評(píng)價(jià)日期']) for detail_url in get_detail_urls(position, list_url): get_message_detail(driver, detail_url, writer, position) time.sleep(get_time()) end_time = time.time() crawl_time = int(end_time - start_time) crawl_minute = crawl_time // 60 crawl_second = crawl_time % 60 print(position, '已爬取結(jié)束?。?!') print('該領(lǐng)導(dǎo)用時(shí):{}分鐘{}秒。'.format(crawl_minute, crawl_second)) driver.quit() time.sleep(5)
獲取該領(lǐng)導(dǎo)的職位信息并為該領(lǐng)導(dǎo)創(chuàng)建一個(gè)獨(dú)立的csv用于保存提取到的留言信息,調(diào)用get_message_detail()方法獲取每條留言的具體信息并保存,計(jì)算出每個(gè)領(lǐng)導(dǎo)的執(zhí)行時(shí)間。
8.合并文件
def merge_csv(): '''將所有文件合并''' file_list = os.listdir('.') csv_list = [] for file in file_list: if file.endswith('.csv'): csv_list.append(file) ## 文件存在則刪除重新創(chuàng)建 if os.path.exists('DATA.csv'): os.remove('DATA.csv') with open('DATA.csv', 'a+', newline='', encoding='gb18030') as f: writer = csv.writer(f, dialect="excel") writer.writerow( ['職位姓名', '留言標(biāo)題', '留言標(biāo)簽1', '留言標(biāo)簽2', '留言日期', '留言內(nèi)容', '回復(fù)人', '回復(fù)內(nèi)容', '回復(fù)日期', '滿意程度', '解決程度分', '辦理態(tài)度分', '辦理速度分', '是否自動(dòng)好評(píng)', '評(píng)價(jià)內(nèi)容', '評(píng)價(jià)日期']) for csv_file in csv_list: with open(csv_file, 'r', encoding='gb18030') as csv_f: reader = csv.reader(csv_f) line_count = 0 for line in reader: line_count += 1 if line_count != 1: writer.writerow( (line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7], line[8], line[9], line[10], line[11], line[12], line[13], line[14], line[15]))
將爬取的所有領(lǐng)導(dǎo)的數(shù)據(jù)進(jìn)行合并。
9.主函數(shù)調(diào)用
def main(): '''主函數(shù)''' fids = get_fid() print('爬蟲(chóng)程序開(kāi)始執(zhí)行:') s_time = time.time() for index, fid in enumerate(fids): try: get_officer_messages(index + 1, fid) except: get_officer_messages(index + 1, fid) print('爬蟲(chóng)程序執(zhí)行結(jié)束!??!') print('開(kāi)始合成文件:') merge_csv() print('文件合成結(jié)束?。?!') e_time = time.time() c_time = int(e_time - s_time) c_minute = c_time // 60 c_second = c_time % 60 print('{}位領(lǐng)導(dǎo)共計(jì)用時(shí):{}分鐘{}秒。'.format(len(fids), c_minute, c_second)) if __name__ == '__main__': '''執(zhí)行主函數(shù)''' main()
主函數(shù)中先獲取領(lǐng)導(dǎo)所有留言,再合并所有數(shù)據(jù)文件,完成整個(gè)爬取過(guò)程,并統(tǒng)計(jì)整個(gè)程序的運(yùn)行時(shí)間,便于分析運(yùn)行效率。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
新聞名稱:?jiǎn)芜M(jìn)程+selenium模擬怎么爬取領(lǐng)導(dǎo)留言并整合成CSV文件
轉(zhuǎn)載源于:http://fisionsoft.com.cn/article/gephed.html