python多線程+代理池爬取天天基金網(wǎng)、股票數(shù)據(jù)過(guò)程解析
簡(jiǎn)介
提到爬蟲(chóng),大部分人都會(huì)想到使用Scrapy工具,但是僅僅停留在會(huì)使用的階段。為了增加對(duì)爬蟲(chóng)機(jī)制的理解,我們可以手動(dòng)實(shí)現(xiàn)多線程的爬蟲(chóng)過(guò)程,同時(shí),引入IP代理池進(jìn)行基本的反爬操作。
本次使用天天基金網(wǎng)進(jìn)行爬蟲(chóng),該網(wǎng)站具有反爬機(jī)制,同時(shí)數(shù)量足夠大,多線程效果較為明顯。
技術(shù)路線
- IP代理池
- 多線程
- 爬蟲(chóng)與反爬
編寫(xiě)思路
首先,開(kāi)始分析天天基金網(wǎng)的一些數(shù)據(jù)。經(jīng)過(guò)抓包分析,可知:
./fundcode_search.js包含所有基金的數(shù)據(jù),同時(shí),該地址具有反爬機(jī)制,多次訪問(wèn)將會(huì)失敗的情況。
同時(shí),經(jīng)過(guò)分析可知某只基金的相關(guān)信息地址為:fundgz.1234567.com.cn/js/ + 基金代碼 + .js
分析完天天基金網(wǎng)的數(shù)據(jù)后,搭建IP代理池,用于反爬作用。點(diǎn)擊這里搭建代理池,由于該作者提供了一個(gè)例子,所以本代碼里面直接使用的是作者提供的接口。如果你需要更快速的獲取到普匿IP,則可以自行搭建一個(gè)本地IP代理池。
# 返回一個(gè)可用代理,格式為ip:端口
# 該接口直接調(diào)用github代理池項(xiàng)目給的例子,故不保證該接口實(shí)時(shí)可用
# 建議自己搭建一個(gè)本地代理池,這樣獲取代理的速度更快
# 代理池搭建github地址https://github.com/1again/ProxyPool
# 搭建完畢后,把下方的proxy.1again.cc改成你的your_server_ip,本地搭建的話可以寫(xiě)成127.0.0.1或者localhost
def get_proxy():
data_json = requests.get("http://proxy.1again.cc:35050/api/v1/proxy/?type=2").text
data = json.loads(data_json)
return data['data']['proxy']
搭建完IP代理池后,我們開(kāi)始著手多線程爬取數(shù)據(jù)的工作。一旦使用多線程,則需要考慮到數(shù)據(jù)的讀寫(xiě)順序問(wèn)題。這里使用python中的隊(duì)列queue進(jìn)行存儲(chǔ)基金代碼,不同線程分別從這個(gè)queue中獲取基金代碼,并訪問(wèn)指定基金的數(shù)據(jù)。由于queue的讀取和寫(xiě)入是阻塞的,所以可以確保該過(guò)程不會(huì)出現(xiàn)讀取重復(fù)和讀取丟失基金代碼的情況。
# 將所有基金代碼放入先進(jìn)先出FIFO隊(duì)列中
# 隊(duì)列的寫(xiě)入和讀取都是阻塞的,故在多線程情況下不會(huì)亂
# 在不使用框架的前提下,引入多線程,提高爬取效率
# 創(chuàng)建一個(gè)隊(duì)列
fund_code_queue = queue.Queue(len(fund_code_list))
# 寫(xiě)入基金代碼數(shù)據(jù)到隊(duì)列
for i in range(len(fund_code_list)):
#fund_code_list[i]也是list類型,其中該list中的第0個(gè)元素存放基金代碼
fund_code_queue.put(fund_code_list[i][0])
現(xiàn)在,開(kāi)始編寫(xiě)如何獲取指定基金的代碼。首先,該函數(shù)必須先判斷queue是否為空,當(dāng)不為空的時(shí)候才可進(jìn)行獲取基金數(shù)據(jù)。同時(shí),當(dāng)發(fā)現(xiàn)訪問(wèn)失敗時(shí),則必須將我們剛剛?cè)〕龅幕鸫a重新放回到隊(duì)列中去,這樣才不會(huì)導(dǎo)致基金代碼丟失。
# 獲取基金數(shù)據(jù)
def get_fund_data():
# 當(dāng)隊(duì)列不為空時(shí)
while (not fund_code_queue.empty()):
# 從隊(duì)列讀取一個(gè)基金代碼
# 讀取是阻塞操作
fund_code = fund_code_queue.get()
# 獲取一個(gè)代理,格式為ip:端口
proxy = get_proxy()
# 獲取一個(gè)隨機(jī)user_agent和Referer
header = {'User-Agent': random.choice(user_agent_list),
'Referer': random.choice(referer_list)
}
try:
req = requests.get("http://fundgz.1234567.com.cn/js/" + str(fund_code) + ".js", proxies={"http": proxy}, timeout=3, headers=header)
except Exception:
# 訪問(wèn)失敗了,所以要把我們剛才取出的數(shù)據(jù)再放回去隊(duì)列中
fund_code_queue.put(fund_code)
print("訪問(wèn)失敗,嘗試使用其他代理訪問(wèn)")
當(dāng)訪問(wèn)成功時(shí),則說(shuō)明能夠成功獲得基金的相關(guān)數(shù)據(jù)。當(dāng)我們?cè)趯⑦@些數(shù)據(jù)存入到一個(gè).csv文件中,會(huì)發(fā)現(xiàn)數(shù)據(jù)出現(xiàn)錯(cuò)誤。這是由于多線程導(dǎo)致,由于多個(gè)線程同時(shí)對(duì)該文件進(jìn)行寫(xiě)入,導(dǎo)致出錯(cuò)。所以需要引入一個(gè)線程鎖,確保每次只有一個(gè)線程寫(xiě)入。
# 申請(qǐng)獲取鎖,此過(guò)程為阻塞等待狀態(tài),直到獲取鎖完畢
mutex_lock.acquire()
# 追加數(shù)據(jù)寫(xiě)入csv文件,若文件不存在則自動(dòng)創(chuàng)建
with open('./fund_data.csv', 'a+', encoding='utf-8') as csv_file:
csv_writer = csv.writer(csv_file)
data_list = [x for x in data_dict.values()]
csv_writer.writerow(data_list)
# 釋放鎖
mutex_lock.release()
至此,大部分工作已經(jīng)完成了。為了更好地實(shí)現(xiàn)偽裝效果,我們對(duì)header進(jìn)行隨機(jī)選擇。
# user_agent列表
user_agent_list = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36'
]
# referer列表
referer_list = [
'http://fund.eastmoney.com/110022.html',
'http://fund.eastmoney.com/110023.html',
'http://fund.eastmoney.com/110024.html',
'http://fund.eastmoney.com/110025.html'
]
# 獲取一個(gè)隨機(jī)user_agent和Referer
header = {'User-Agent': random.choice(user_agent_list),
'Referer': random.choice(referer_list)
}
最后,在main中,開(kāi)啟線程即可。
# 創(chuàng)建一個(gè)線程鎖,防止多線程寫(xiě)入文件時(shí)發(fā)生錯(cuò)亂
mutex_lock = threading.Lock()
# 線程數(shù)為50,在一定范圍內(nèi),線程數(shù)越多,速度越快
for i in range(50):
t = threading.Thread(target=get_fund_data,name='LoopThread'+str(i))
t.start()
通過(guò)對(duì)多線程和IP代理池的實(shí)踐操作,能夠更加深入了解多線程和爬蟲(chóng)的工作原理。當(dāng)你在使用一些爬蟲(chóng)框架的時(shí)候,就能夠做到快速定位錯(cuò)誤并解決錯(cuò)誤。
數(shù)據(jù)格式
000056,建信消費(fèi)升級(jí)混合,2019-03-26,1.7740,1.7914,0.98,2019-03-27 15:00
000031,華夏復(fù)興混合,2019-03-26,1.5650,1.5709,0.38,2019-03-27 15:00
000048,華夏雙債增強(qiáng)債券C,2019-03-26,1.2230,1.2236,0.05,2019-03-27 15:00
000008,嘉實(shí)中證500ETF聯(lián)接A,2019-03-26,1.4417,1.4552,0.93,2019-03-27 15:00
000024,大摩雙利增強(qiáng)債券A,2019-03-26,1.1670,1.1674,0.04,2019-03-27 15:00
000054,鵬華雙債增利債券,2019-03-26,1.1697,1.1693,-0.03,2019-03-27 15:00
000016,華夏純債債券C,2019-03-26,1.1790,1.1793,0.03,2019-03-27 15:00
功能截圖

配置說(shuō)明
# 確保安裝以下庫(kù),如果沒(méi)有,請(qǐng)?jiān)趐ython3環(huán)境下執(zhí)行pip install 模塊名 import requests import random import re import queue import threading import csv import json
補(bǔ)充
完整版源代碼存放在github上,有需要的可以下載
項(xiàng)目持續(xù)更新,歡迎您star本項(xiàng)目
,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值
相關(guān)文章
在Python的Django框架中編寫(xiě)編譯函數(shù)
這篇文章主要介紹了在Python的Django框架中編寫(xiě)編譯函數(shù),配合模版標(biāo)簽在模版中進(jìn)行使用<需要的朋友可以參考下2015-07-07
Python編程實(shí)現(xiàn)兩個(gè)文件夾里文件的對(duì)比功能示例【包含內(nèi)容的對(duì)比】
這篇文章主要介紹了Python編程實(shí)現(xiàn)兩個(gè)文件夾里文件的對(duì)比功能,包含內(nèi)容的對(duì)比操作,涉及Python文件與目錄的遍歷、比較、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
django2.2安裝錯(cuò)誤最全的解決方案(小結(jié))
這篇文章主要介紹了django2.2安裝錯(cuò)誤最全的解決方案(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
pyecharts動(dòng)態(tài)軌跡圖的實(shí)現(xiàn)示例
這篇文章主要介紹了pyecharts動(dòng)態(tài)軌跡圖的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
基于python的selenium兩種文件上傳操作實(shí)現(xiàn)詳解
這篇文章主要介紹了基于python的selenium兩種文件上傳操作實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
Tensorflow實(shí)現(xiàn)酸奶銷(xiāo)量預(yù)測(cè)分析
這篇文章主要為大家詳細(xì)介紹了Tensorflow酸奶銷(xiāo)量預(yù)測(cè)分析,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07

