爬蟲(chóng)的目標(biāo)
- 我的目的是爬取某直播網(wǎng)站某一天所有頻道的網(wǎng)絡(luò)流量數(shù)據(jù),每一個(gè)頻道有一個(gè)自己的頁(yè)面,顯示可視化后的流量數(shù)據(jù)鹉动,而要獲取這個(gè)頻道頁(yè)面的url,需要先訪問(wèn)另一個(gè)列表頁(yè)面宏邮,每一個(gè)列表頁(yè)面包含了10個(gè)頻道的屬性信息(如channelid, starttime, endtime)泽示。因此缸血,爬蟲(chóng)過(guò)程整體分兩步:
- 訪問(wèn)列表頁(yè)面,通過(guò)指定日期和頁(yè)數(shù)設(shè)置http請(qǐng)求的params械筛。獲取返回的頁(yè)面內(nèi)容后捎泻,保存到本地文件。
- 讀取本地文件中保存的頻道屬性信息埋哟,作為訪問(wèn)頻道頁(yè)面請(qǐng)求的params笆豁,訪問(wèn)頻道頁(yè)面,獲取返回的內(nèi)容(即頻道的流量數(shù)據(jù))后定欧,保存到本地文件
第一步:爬取列表頁(yè)面
瀏覽器訪問(wèn)列表頁(yè)面時(shí)怎么做的渔呵?
- 通過(guò)chrome瀏覽器的DevTools(快捷鍵F12)中對(duì)訪問(wèn)列表頁(yè)面的網(wǎng)絡(luò)監(jiān)控,可以知道在最終成功訪問(wèn)到目標(biāo)頁(yè)面之前砍鸠,實(shí)際上先跳轉(zhuǎn)到了4個(gè)別的頁(yè)面(xxpreLogin, xxcaLogin, xxLogin, sendxxToken)進(jìn)行登陸扩氢,最后才返回我要的訪問(wèn)列表的內(nèi)容。以上是我在打開(kāi)瀏覽器第一次訪問(wèn)該頁(yè)面的過(guò)程爷辱,但后來(lái)在頁(yè)面內(nèi)點(diǎn)擊轉(zhuǎn)到別的頁(yè)數(shù)時(shí)录豺,只有單純的一條訪問(wèn)請(qǐng)求了。為什么之后不用登陸認(rèn)證呢饭弓?因?yàn)楹髞?lái)的請(qǐng)求中帶有第一次認(rèn)證后得到的cookie双饥,服務(wù)器
確認(rèn)過(guò)眼神驗(yàn)證了cookie后,就同意給出所請(qǐng)求的頁(yè)面數(shù)據(jù)弟断。
我用什么方法能到達(dá)列表頁(yè)面咏花?
第一個(gè)方法:模擬整個(gè)訪問(wèn)列表的步驟,包括登陸認(rèn)證等步驟阀趴,獲取最終訪問(wèn)列表頁(yè)面時(shí)所需的信息(如cookie, token)后再訪問(wèn)昏翰。這是最符合瀏覽器思路的一個(gè)方法,但登陸步驟繁多刘急;對(duì)于沒(méi)有詳細(xì)學(xué)習(xí)過(guò)HTML和JS的我來(lái)說(shuō)棚菊,照貓畫(huà)虎地發(fā)送請(qǐng)求容易,但理解對(duì)方發(fā)來(lái)的response就比較難了叔汁。另外统求,這4個(gè)別的頁(yè)面有hppts請(qǐng)求,涉及到數(shù)據(jù)的加密据块,因此要考慮的因素很多码邻。
所以我換了一個(gè) 更粗暴直接的方法:直接查看訪問(wèn)列表頁(yè)面的最后一步帶了哪些cookie,如果我?guī)贤瑯拥腸ookie瑰钮,訪問(wèn)同樣的url冒滩,肯定也能訪問(wèn)成功。此處確定了我要從瀏覽器監(jiān)控頁(yè)面復(fù)制的信息:url(帶params)浪谴,cookie开睡。把復(fù)制的cookie保存到本地文件里,我的程序訪問(wèn)時(shí)從文件中讀取cookie并添加到請(qǐng)求的headers中苟耻,把url中的params分離出來(lái)重新構(gòu)造同格式但不同值的params篇恒,baseurl/params/headers準(zhǔn)備完畢后就可以發(fā)送請(qǐng)求了。
-
寫(xiě)http請(qǐng)求時(shí)需要明確的三個(gè)基本內(nèi)容:
- 訪問(wèn)該頁(yè)面時(shí)實(shí)際請(qǐng)求的url是什么(瀏覽器地址欄的url通常不是請(qǐng)求數(shù)據(jù)所用的實(shí)際url)
- 訪問(wèn)該頁(yè)面需要的請(qǐng)求params是什么(比如請(qǐng)求第幾頁(yè))
- 訪問(wèn)該頁(yè)面的headers要有什么(比如最重要的cookie)
-
這里我使用了基本的requests庫(kù)凶杖,代碼如下:
from urllib import parse from urllib.parse import urlsplit, parse_qs import requests # 讀取cookie cookie_filename = 'cookies.txt' cookiefile = open(cookie_filename, 'r') cookies = {} for line in cookiefile.read().split(';'): name, value = line.strip().split('=',1) cookies[name] = value cookiefile.close() # 訪問(wèn)列表的start_page到end_page頁(yè) url = 'http://xxxx.xxxxxx.com/xxx/xxxx.do?' \ 'startTime=xxxx&endTime=xxxx¤tPage=xxxx&pt=xxxx' start_page, end_page = 1, 1000 for page in range(start_page, end_page): baseurl = parse.splitquery(url)[0] params = parse_qs(urlsplit(url).query) params['currentPage'] = page params['startTime'] = '2018-01-01 00:00:00' params['endTime'] = '2018-01-01 23:59:59' response = requests.get(baseurl, params=params, cookies=cookies) content = response.content.decode() pagefile = 'page' + str(page) + '.txt' with open(pagefile, 'w', encoding='utf-8') as pfile: pfile.write(content)
像上面說(shuō)的一樣胁艰,先復(fù)制下來(lái)url到代碼中,再?gòu)?fù)制cookies到文件中智蝠,這個(gè)代碼就能成功運(yùn)行了腾么。 BUT,好景不長(zhǎng)杈湾,這段代碼在成功運(yùn)行了大約不到十分鐘后解虱,突然取不到數(shù)據(jù)而是取回了像初次訪問(wèn)一樣的登陸認(rèn)證頁(yè)面。經(jīng)過(guò)一番分析漆撞,我發(fā)現(xiàn)目標(biāo)頁(yè)面的url中有一個(gè)param實(shí)際是跟時(shí)間有關(guān)的(指上面代碼中的pt)殴泰,cookies中也有類似服務(wù)器端的心跳時(shí)間cookie,多半是服務(wù)器看我?guī)У倪@個(gè)心跳cookie太老了不在它可以回答的時(shí)間區(qū)間內(nèi)浮驳,所以返回讓我重新認(rèn)證悍汛。另外,瀏覽器每次發(fā)出請(qǐng)求(哪怕是請(qǐng)求同樣的頁(yè)面)時(shí)有一個(gè)cookie值都會(huì)隨機(jī)改變至会,目前分析應(yīng)該是和證書(shū)有關(guān)离咐。所以,雖然用同樣的一對(duì)pt和cookie大約能持續(xù)幾分鐘的成功訪問(wèn)奉件,但如果要在崩了以后還能繼續(xù)訪問(wèn)宵蛀,只是更新pt到最新時(shí)間經(jīng)嘗試是不行的。好在我要訪問(wèn)的列表頁(yè)面總頁(yè)數(shù)不是很多瓶蚂,所以我將代碼稍加修改糖埋,記錄每次崩時(shí)訪問(wèn)到哪一頁(yè)了,然后用瀏覽器再訪問(wèn)一次窃这,復(fù)制新的url和cookies瞳别,從斷掉的地方接著跑。
-
改動(dòng)后的代碼如下:
from urllib import parse from urllib.parse import urlsplit, parse_qs import requests # 讀取cookie cookie_filename = 'cookies.txt' cookiefile = open(cookie_filename, 'r') cookies = {} for line in cookiefile.read().split(';'): name, value = line.strip().split('=',1) cookies[name] = value cookiefile.close() # 訪問(wèn)列表的start_page到end_page頁(yè) url = 'http://xxxx.xxxxxx.com/xxx/xxxx.do?' \ 'startTime=xxxx&endTime=xxxx¤tPage=xxxx&pt=xxxx' start_page, end_page = 1, 1000 for page in range(start_page, end_page): baseurl = parse.splitquery(url)[0] params = parse_qs(urlsplit(url).query) params['currentPage'] = page params['startTime'] = '2018-01-01 00:00:00' params['endTime'] = '2018-01-01 23:59:59' response = requests.get(baseurl, params=params, cookies=cookies) # 如果返回的是登陸認(rèn)證頁(yè)面的地址杭攻,記錄訪問(wèn)到哪一頁(yè)了祟敛,退出循環(huán) resurl = parse.splitquery(response.url)[0] if resurl == 'https://xxxLogin.xxxx.xxx': print('Failed at page '+str(page)+', please restart.') break # 成功訪問(wèn)時(shí),保存數(shù)據(jù) content = response.content.decode() pagefile = 'page' + str(page) + '.txt' with open(pagefile, 'w', encoding='utf-8') as pfile: pfile.write(content)
到此可以爬下來(lái)所有列表頁(yè)面的內(nèi)容了兆解,很明顯馆铁,每十分鐘人工刷新瀏覽器再?gòu)?fù)制粘貼一次是非常耗時(shí)的,這樣的代碼在后面爬取每個(gè)頻道的流量信息時(shí)是不可取的(加載一頁(yè)列表大約1-3秒锅睛,而加載一頁(yè)頻道流量信息可能要10+秒)埠巨,不過(guò)對(duì)于非時(shí)間敏感型的請(qǐng)求來(lái)說(shuō)历谍,上面的代碼是足夠用了。
本著能少一次復(fù)制就少一次的原則辣垒,我希望每次只復(fù)制url望侈,而cookie的信息肯定能從瀏覽器(這里用的chrome)的本地緩存文件中讀,就不需要我花費(fèi)寶貴的時(shí)間復(fù)制到我準(zhǔn)備的文件里了勋桶。因此我查了Chrome瀏覽器在系統(tǒng)中保存cookie的位置脱衙,修改代碼,使 每次開(kāi)始爬取時(shí)直接讀取瀏覽器的cookie例驹。
-
改動(dòng)后的代碼如下:
from urllib import parse from urllib.parse import urlsplit, parse_qs import requests import sqlite3 from win32crypt import CryptUnprotectData # 從Chrome的cookie文件讀取cookie cookie_path = r'C:\Users\ann\AppData\Local\Google\Chrome\User Data\Default\Cookies' host = '.xxx.com' sql = 'select host_key, name, encrypted_value from cookies '\ 'where host_key = \'' + host + '\'' with sqlite3.connect(cookie_path) as conn: cu = conn.cursor() cookies = {name:CryptUnprotectData(encrypted_value)[1].decode() '\ 'for host_key, name, encrypted_value in cu,execute(sql).fetchall()} # 訪問(wèn)列表的start_page到end_page頁(yè) url = 'http://xxxx.xxxxxx.com/xxx/xxxx.do?' \ 'startTime=xxxx&endTime=xxxx¤tPage=xxxx&pt=xxxx' start_page, end_page = 1, 1000 for page in range(start_page, end_page): baseurl = parse.splitquery(url)[0] params = parse_qs(urlsplit(url).query) params['currentPage'] = page params['startTime'] = '2018-01-01 00:00:00' params['endTime'] = '2018-01-01 23:59:59' response = requests.get(baseurl, params=params, cookies=cookies) # 如果返回的是登陸認(rèn)證頁(yè)面的地址捐韩,記錄訪問(wèn)到哪一頁(yè)了,退出循環(huán) resurl = parse.splitquery(response.url)[0] if resurl == 'https://xxxLogin.xxxx.xxx': print('Failed at page '+str(page)+', please restart.') break # 成功訪問(wèn)時(shí)鹃锈,保存數(shù)據(jù) content = response.content.decode() pagefile = 'page' + str(page) + '.txt' with open(pagefile, 'w', encoding='utf-8') as pfile: pfile.write(content)
至此荤胁,每當(dāng)訪問(wèn)崩了,我還是得手動(dòng)用瀏覽器訪問(wèn)一次仪召,復(fù)制url寨蹋,從斷掉的地方繼續(xù)跑。顯然扔茅,即使不用復(fù)制cookies了已旧,這個(gè)代碼還是不能滿足爬取頻道流量的大量數(shù)據(jù)的要求。
因此召娜,爬取頻道流量信息時(shí)我用了另一種思路進(jìn)行訪問(wèn)运褪,不用cookie信息,解放了雙手玖瘸,實(shí)現(xiàn)了全自動(dòng)爬取秸讹。不過(guò),要訪問(wèn)頻道流量信息頁(yè)面雅倒,還得先知道頻道的一些屬性(比如channelId, startTime, endTime)璃诀,把屬性寫(xiě)進(jìn)params,才能獲得正確的頻道頁(yè)面蔑匣,因此劣欢,下一步我們先從爬下來(lái)的列表頁(yè)面中提取頻道屬性信息。
第二步:從列表頁(yè)面文件獲取頻道屬性信息
- 從瀏覽器訪問(wèn)的列表頁(yè)面來(lái)看裁良,一頁(yè)列表有10條頻道屬性信息凿将,因此我到保存的列表頁(yè)面文件中觀察(文件里保存的直接是每個(gè)頻道的數(shù)據(jù),不是這一頁(yè)的html代碼)价脾,每條頻道信息開(kāi)頭都有'"channelhead"'字樣(沒(méi)錯(cuò)帶雙引號(hào)牧抵,這里channelhead不是真實(shí)信息只是我舉個(gè)例子),每條頻道的屬性包括type, channelId, startTime, endTime等侨把。這里我只需要type=1的頻道的信息犀变,因此讀文件時(shí)需要加判斷條件妹孙。
- 這里我結(jié)合了python的find函數(shù)和簡(jiǎn)單的正則表達(dá)式進(jìn)行提取,代碼如下:
import re start_page, end_page = 1, 1000 query_str = ['channelId startTime endTime'] for page in range(start_page, end_page): # 讀出第page頁(yè)的列表頁(yè)面文件 pagefile = 'page' + str(page) + '.txt' pfile = open(pagefile, 'r', encoding='utf-8') data = pfile.read() pfile.close() # 從列表頁(yè)面數(shù)據(jù)有選擇地提取頻道屬性 query_count = data.count('"allowVideo"') index1 = data.find('"allowVideo"') for i in range(query_count-1): # 找到一條頻道信息的區(qū)間[index1, index2] index2 = data.find('"allowVideo"', index1+1) query_data = data[index1:index2] if query_data.find('"type":"1"') > 0: # channelId:先用find找到channelid位置弛作,再用正則匹配提取區(qū)間內(nèi)的數(shù)字 index_chid = query_data.find('channelId') chid = re.sub(r'\D', '', query_data[index_chid, index_chid+30]) # startTime index_st = query_data.find('startTime') st = query_data[index_st+12, index_st+19] # endTime index_et = query_data.find('endTime') et = query_data[index_et+10, index_et+19] str = chid + ' ' + st + ' ' + et query_str.append(str) index1 = index2 # 把所有的query存入另一個(gè)文件 # (實(shí)際上我得到的query的屬性遠(yuǎn)不止這些涕蜂,因此是分很多文件存的华匾, # 由于文件讀寫(xiě)操作不是此次爬蟲(chóng)的重點(diǎn)映琳,所以這里不細(xì)講) query_filename = 'query.txt' with open(query_filename, 'w', encoding='utf-8') as qfile: for item in query_str: qfile.write(item + '\n')
- 到此我提取了所有需要的頻道屬性的信息,只待拿著這些信息去請(qǐng)求頻道網(wǎng)絡(luò)流量頁(yè)面了
第三步:獲取每個(gè)頻道網(wǎng)絡(luò)流量頁(yè)面
第一步的方法蜘拉,雖然能繞過(guò)登陸認(rèn)證的步驟萨西,也能自動(dòng)從Chrome的本地cookie文件中提取我要的cookie,但每隔幾分鐘我還是得手動(dòng)刷新瀏覽器并復(fù)制其url粘貼到代碼中旭旭,整個(gè)操作非常笨拙耗時(shí)效率低下谎脯。于是我又換了一個(gè)思路:有什么方法能 直接調(diào)用Chrome瀏覽器來(lái)訪問(wèn) 嗎?我不想知道它訪問(wèn)的細(xì)節(jié)持寄,只要給我返回的最終結(jié)果就好源梭。于是我發(fā)現(xiàn)了 selenium庫(kù)的webdriver 方法。
調(diào)用webdriver.Chrome()會(huì)生成一個(gè)瀏覽器對(duì)象稍味,瀏覽器對(duì)象的.get(url)方法就能使瀏覽器自己帶上合適的cookie并返回相應(yīng)頁(yè)面废麻,瀏覽器的.page_source屬性就是頁(yè)面的內(nèi)容啦。
-
使用selenium庫(kù)的webdriver調(diào)用Chrome瀏覽器訪問(wèn)頻道頁(yè)面并存入文件的代碼如下:
from selenium import webdriver import time form urllib import parse import os baseurl = 'http://xxx.xxxx.xxx/xxx.do' # query文件的前綴模庐,每個(gè)query文件都有多條channel的屬性信息 query_fileadd = r'D:\xxx\query' # 每個(gè)query文件對(duì)應(yīng)一個(gè)裝channelpage的文件夾 channelpage_fileadd = r'D:\xxx\ChannelPages\Query' start, end = 1, 10 # 初始化一個(gè)Chrome的driver browser = webdriver.Chrome() for i in range(start, end+1): # 讀取第i個(gè)query文件的所有queries query_filename = query_fileadd + str(i) + '.txt' qfile = open(query_filename, 'r') query_list = [] for line in qfile: query_list.append(line) qfile.close() # 確保創(chuàng)建了channelpage的路徑 cpdir = os.path.join(channelpage_fileadd, str(i)) if not os.path.exists(cpdir): os.mkdir(cpdir) # 根據(jù)query_list發(fā)送http請(qǐng)求獲取channel page for i in range(len(query_list)) # url的拼接 q = query_list[i].split(' ') chid, st, et = q[0], q[1], q[2] pt = str(int(time.time())) params = dict(startTime=st, endTime=et, channelId=chid, pt=pt) url = baseurl + '?' + parse.urlencode(query=params) # 獲取channel page的數(shù)據(jù) browser.get(url) channelpagedata = browser.page_source # 寫(xiě)入channel文件 cpfname = os.path.join(cpdir, 'channel'+str(i)+'.txt') with open(cpfname, 'w', encoding='utf-8') as cf: cf.write(channelpagedata) browser.quit()
- 上面的代碼實(shí)現(xiàn)了一鍵訪問(wèn)下載頻道頁(yè)面的目標(biāo)烛愧,解放了雙手,非常開(kāi)心掂碱!然而過(guò)了幾分鐘之后怜姿,我眉頭一皺,發(fā)現(xiàn) 事情并沒(méi)有這么簡(jiǎn)單疼燥。
- 之前提到過(guò)沧卢,瀏覽器訪問(wèn)一個(gè)頻道頁(yè)面大約要10+秒,導(dǎo)致上面調(diào)用瀏覽器的代碼下載非常龜速醉者,那么如何能讓下載速度提高呢但狭? 多線程。這里我需要的數(shù)據(jù)沒(méi)有下載先后的要求湃交,存數(shù)據(jù)的文件也是每個(gè)頻道有獨(dú)立的文件熟空,所以甚至連鎖也用不上。
- 每個(gè)線程負(fù)責(zé)的任務(wù):這里我有多個(gè)query的文件搞莺,每個(gè)文件有多條channel的屬性息罗,每條channel屬性對(duì)應(yīng)訪問(wèn)一次channel頁(yè)面。假設(shè)query文件一共50個(gè)才沧,每個(gè)文件有1000條屬性迈喉,簡(jiǎn)單來(lái)分配的話绍刮,每條線程負(fù)責(zé)10個(gè)query文件共5條線程就行(如果內(nèi)存容量比較大,那可以更多條挨摸,速度會(huì)相對(duì)更快)孩革。
- 這里多線程我使用的 threading 庫(kù),多線程訪問(wèn)并存儲(chǔ)的代碼如下:
from selenium import webdriver from urllib import parse import os import threading def getChannelPages(startpage, endpage, query_fileadd, channelpage_fileadd, baseurl, params): browser = webdriver.Chrome() for i in range(startpage, endpage, 100): # 讀取文件的query存入query_list qfname = query_fileadd + str(i) + '.txt' qfile = open(qfname) query_list = [] for line in qfile: query_list.append(line) qfile.close() # 確保創(chuàng)建了存channel page的路徑 cpdir = os.path.join(channelpage_fileadd, str(i)) if not os.path.exists(cpdir): os.mkdir(cpdir) # 根據(jù)query_list發(fā)送http請(qǐng)求獲取channel page for index in range(len(query_list)): # url的拼接 query = query_list[index].split(' ') chid, st, et = query[0], query[1], query[2] pt = str(int(time.time())) params['startTime'] = st params['endTime'] = et params['channelId'] = chid url = baseurl + '?' + parse.urlencode(query=params) # 獲取channel page數(shù)據(jù) browser.get(url) channelpagedata = browser.page_source # 寫(xiě)入channel文件 cpfadd = os.path.join(cpdir, 'channel' + str(index) + '.txt') with open(cpfadd, 'w', encoding='utf-8') as cf: cf.write(channelpagedata) browser.quit() if __name__ == '__main__': query_fileadd = r'D:\xxx\query' channelpage_fileadd = r'D\xxx\ChannelPages' # channel頁(yè)面參數(shù)設(shè)置: baseurl, params baseurl = 'http://xxxx.xxxx.xxx/xxx.do' params = dict(startTime='',endTime='',channelId='') threads = [] # 初始化各線程 startpage, endpage = 1, 1000 for i in range(startpage, endpage, 200): t = threading.Thread(target=getChannelPages, args=(i, i+199, query_fileadd, baseurl, params)) threads.append(t) # 開(kāi)始表演 for t in threads: t.start() for t in threads: t.join()
- 目前代碼實(shí)現(xiàn)了多線程爬蟲(chóng)的功能得运,大幅提高了爬蟲(chóng)的速度膝蜈,不過(guò)還有很多可以優(yōu)化的部分(比如換一種線程負(fù)責(zé)的功能,或者改成多進(jìn)程熔掺,還有異步饱搏,除了線程以外,對(duì)頻道屬性的提取可以用更高效的正則表達(dá)式而不是find函數(shù))置逻。
完整代碼
- 下面是爬取列表頁(yè)推沸,提取query,爬取頻道頁(yè)的完整代碼券坞,其中爬取列表頁(yè)也改成多線程方式了鬓催。
from selenium import webdriver from urllib import parse import time import re import os import threading def getHistoryPages(startpage, endpage, listpage_fileadd, baseurl, params): # 訪問(wèn)第startpage頁(yè)到第endpage頁(yè)的列表頁(yè)面,每100頁(yè)存入一個(gè)文件 browser = webdriver.Chrome() for bigpage in range(startpage, endpage, 100): if bigpage+99 > endpage: end = endpage else: end = bigpage + 99 page_data = [] for page in range(bigpage, end+1): params['currentPage'] = str(page) params['pt'] = str(int(time.time)) url = baseurl + '?' + parse.urlencode(query=params) browser.get(url) page_data.append(browser.page_source) listpage_filename = listpage_fileadd + str(bigpage) + '-' + str(bigpage+99) + '.txt' lfile = open(listpage_filename, 'w', encoding='utf-8') for item in page_data: lfile.write(item+'\n') lfile.close() del page_data browser.quit() def extractQueries(listpage_filename, query_filename): # 把給定文件里的page data轉(zhuǎn)換成query query_str = ['channelId startTime endTime'] file = open(listpage_filename, 'r', encoding='utf-8') data = file.read() file.close() query_count = data.count('"allowVideo"') index1 = data.find('"allowVideo"') for i in range(query_count - 1): index2 = data.find('"allowVideo"', index1 + 1) query_data = data[index1:index2] if query_data.find('"type":"1"'): index_chid = query_data.find('channelId') chid = re.sub(r'\D', '', query_data[index_chid, index_chid+30]) index_st = query_data.find('startTime') st = query_data[index_st+12, index_st+19] index_et = query_data.find('endTime') et = query_data[index_et+10, index_et+19] str = chid + ' ' + st + ' ' + et query_str.append(str) index1 = index2 # 把query_str寫(xiě)入文件 qfile = open(query_filename, 'w', encoding='utf-8') for item in query_str: qfile.write(item+'\n') def getChannelPages(startpage, endpage, query_fileadd, channelpage_fileadd, baseurl, params): browser = webdriver.Chrome() for i in range(startpage, endpage, 100): # 讀取文件的query存入query_list qfname = query_fileadd + str(i) + '-' + str(i+99) '.txt' qfile = open(qfname) query_list = [] for line in qfile: query_list.append(line) qfile.close() # 確保創(chuàng)建了存channel page的路徑 cpdir = os.path.join(channelpage_fileadd, str(i) + '-' + str(i+99)) if not os.path.exists(cpdir): os.mkdir(cpdir) # 根據(jù)query_list發(fā)送http請(qǐng)求獲取channel page for index in range(len(query_list)): # url的拼接 query = query_list[index].split(' ') chid, st, et = query[0], query[1], query[2] pt = str(int(time.time())) params['startTime'] = st params['endTime'] = et params['channelId'] = chid url = baseurl + '?' + parse.urlencode(query=params) # 獲取channel page數(shù)據(jù) browser.get(url) channelpagedata = browser.page_source # 寫(xiě)入channel文件 cpfadd = os.path.join(cpdir, 'channel' + str(index) + '.txt') with open(cpfadd, 'w', encoding='utf-8') as cf: cf.write(channelpagedata) browser.quit() if __name__ == '__main__': listpage_fileadd = r'D:\xxx\xxx\page' query_fileadd = r'D:\xxx\query' channelpage_fileadd = r'D\xxx\ChannelPages' # 列表頁(yè)面參數(shù)設(shè)置: baseurl, params baseurl = 'http://xxxx.xxxx.xxx/xxx.do' params = dict(startTime='2018-01-01 00:00:00', endTime='2018-01-01 00:00:00') startpage, endpage = 1, 1000 threads = [] for page in range(startpage, endpage, 200): t = threading.Thread(target=getHistoryPages, args=(page, page+199, listpage_fileadd, baseurl, params)) threads.append(t) for t in threads: t.start() for t in threads: t.join() # 從channel list文件中提取channel的屬性 startpage, endpage = 1, 1000 for listpage in range(startpage, endpage, 100): listpage_filename = listpage_fileadd + str(listpage) + '-' + str(listpage+99) + '.txt' query_filename = query_fileadd + str(listpage) + '-' + str(listpage+99) + '.txt' extractQueries(listpage_filename, query_filename) # channel頁(yè)面參數(shù)設(shè)置: baseurl, params baseurl = 'http://xxxx.xxxx.xxx/xxx.do' params = dict(startTime='',endTime='',channelId='') threads = [] startpage, endpage = 1, 1000 for i in range(startpage, endpage, 200): t = threading.Thread(target=getChannelPages, args=(i, i+199, query_fileadd, baseurl, params)) threads.append(t) for t in threads: t.start() for t in threads: t.join()
后續(xù)
- 爬下來(lái)這么多數(shù)據(jù)恨锚,肯定不能存在同一個(gè)電腦里宇驾,因此之后還經(jīng)歷了設(shè)置ftp server等步驟對(duì)爬下來(lái)的數(shù)據(jù)進(jìn)行轉(zhuǎn)移,這里不細(xì)講了眠冈,網(wǎng)上有很多教程飞苇。