1:首先,開始分析天天基金網的一些數據。經過抓包分析,可知: ./fundcode_search.js包含所有基金的數據,同時,該地址具有反爬機制,多次訪問將會失敗的情況。
2:同時,經過分析可知某只基金的相關信息地址為:fundgz.1234567.com.cn/js/ + 基金代碼 + .js
3:分析完天天基金網的數據后,搭建IP代理池,用於反爬作用。
# 返回一個可用代理,格式為ip:端口 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']
4:搭建完IP代理池后,我們開始着手多線程爬取數據的工作。一旦使用多線程,則需要考慮到數據的讀寫順序問題。這里使用python中的隊列queue進行存儲基金代碼,不同線程分別從這個queue中獲取基金代碼,並訪問指定基金的數據。
# 將所有基金代碼放入先進先出FIFO隊列中 # 隊列的寫入和讀取都是阻塞的,故在多線程情況下不會亂 # 在不使用框架的前提下,引入多線程,提高爬取效率 # 創建一個隊列 fund_code_queue = queue.Queue(len(fund_code_list)) # 寫入基金代碼數據到隊列 for i in range(len(fund_code_list)): #fund_code_list[i]也是list類型,其中該list中的第0個元素存放基金代碼 fund_code_queue.put(fund_code_list[i][0])
5:現在,開始編寫如何獲取指定基金的代碼。
# 獲取基金數據 def get_fund_data(): # 當隊列不為空時 while (not fund_code_queue.empty()): # 從隊列讀取一個基金代碼 # 讀取是阻塞操作 fund_code = fund_code_queue.get() # 獲取一個代理,格式為ip:端口 proxy = get_proxy() # 獲取一個隨機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: # 訪問失敗了,所以要把我們剛才取出的數據再放回去隊列中 fund_code_queue.put(fund_code) print("訪問失敗,嘗試使用其他代理訪問")
6:當訪問成功時,則說明能夠成功獲得基金的相關數據。當我們在將這些數據存入到一個.csv文件中,會發現數據出現錯誤。這是由於多線程導致,由於多個線程同時對該文件進行寫入,導致出錯。所以需要引入一個線程鎖,確保每次只有一個線程寫入。
# 申請獲取鎖,此過程為阻塞等待狀態,直到獲取鎖完畢 mutex_lock.acquire() # 追加數據寫入csv文件,若文件不存在則自動創建 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()
7:至此,大部分工作已經完成了。為了更好地實現偽裝效果,我們對header進行隨機選擇。
# 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' ] # 獲取一個隨機user_agent和Referer header = {'User-Agent': random.choice(user_agent_list), 'Referer': random.choice(referer_list) }
8:最后,在main中,開啟線程即可。
# 創建一個線程鎖,防止多線程寫入文件時發生錯亂 mutex_lock = threading.Lock() # 線程數為50,在一定范圍內,線程數越多,速度越快 for i in range(50): t = threading.Thread(target=get_fund_data,name='LoopThread'+str(i)) t.start()
數據格式
000056,建信消費升級混合,2019-03-26,1.7740,1.7914,0.98,2019-03-27 15:00
000031,華夏復興混合,2019-03-26,1.5650,1.5709,0.38,2019-03-27 15:00
000048,華夏雙債增強債券C,2019-03-26,1.2230,1.2236,0.05,2019-03-27 15:00
000008,嘉實中證500ETF聯接A,2019-03-26,1.4417,1.4552,0.93,2019-03-27 15:00
000024,大摩雙利增強債券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