多線程+代理池爬取每天基金網、股票數據(無需使用爬蟲框架)

@[TOC]html

簡介

提到爬蟲,大部分人都會想到使用Scrapy工具,可是僅僅停留在會使用的階段。爲了增長對爬蟲機制的理解,咱們能夠手動實現多線程的爬蟲過程,同時,引入IP代理池進行基本的反爬操做。python

本次使用每天基金網進行爬蟲,該網站具備反爬機制,同時數量足夠大,多線程效果較爲明顯。git

技術路線

  • IP代理池
  • 多線程
  • 爬蟲與反爬

編寫思路

  1. 首先,開始分析每天基金網的一些數據。通過抓包分析,可知:

./fundcode_search.js包含全部基金的數據,同時,該地址具備反爬機制,屢次訪問將會失敗的狀況。github

  1. 同時,通過分析可知某隻基金的相關信息地址爲:fundgz.1234567.com.cn/js/ + 基金代碼 + .js
  2. 分析完每天基金網的數據後,搭建IP代理池,用於反爬做用。點擊這裏搭建代理池,因爲該做者提供了一個例子,因此本代碼裏面直接使用的是做者提供的接口。若是你須要更快速的獲取到普匿IP,則能夠自行搭建一個本地IP代理池。
# 返回一個可用代理,格式爲ip:端口
    # 該接口直接調用github代理池項目給的例子,故不保證該接口實時可用
    # 建議本身搭建一個本地代理池,這樣獲取代理的速度更快
    # 代理池搭建github地址https://github.com/1again/ProxyPool
    # 搭建完畢後,把下方的proxy.1again.cc改爲你的your_server_ip,本地搭建的話能夠寫成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']
  1. 搭建完IP代理池後,咱們開始着手多線程爬取數據的工做。一旦使用多線程,則須要考慮到數據的讀寫順序問題。這裏使用python中的隊列queue進行存儲基金代碼,不一樣線程分別從這個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])
  1. 如今,開始編寫如何獲取指定基金的代碼。首先,該函數必須先判斷queue是否爲空,當不爲空的時候纔可進行獲取基金數據。同時,當發現訪問失敗時,則必須將咱們剛剛取出的基金代碼從新放回到隊列中去,這樣纔不會致使基金代碼丟失。
# 獲取基金數據
    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("訪問失敗,嘗試使用其餘代理訪問")
  1. 當訪問成功時,則說明可以成功得到基金的相關數據。當咱們在將這些數據存入到一個.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()
  1. 至此,大部分工做已經完成了。爲了更好地實現假裝效果,咱們對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)
    }
  1. 最後,在main中,開啓線程便可。
# 建立一個線程鎖,防止多線程寫入文件時發生錯亂
    mutex_lock = threading.Lock()
    # 線程數爲50,在必定範圍內,線程數越多,速度越快
    for i in range(50):
        t = threading.Thread(target=get_fund_data,name='LoopThread'+str(i))
        t.start()
  1. 經過對多線程和IP代理池的實踐操做,可以更加深刻了解多線程和爬蟲的工做原理。當你在使用一些爬蟲框架的時候,就可以作到快速定位錯誤並解決錯誤。

數據格式

000056,建信消費升級混合,2019-03-26,1.7740,1.7914,0.98,2019-03-27 15:00web

000031,華夏復興混合,2019-03-26,1.5650,1.5709,0.38,2019-03-27 15:00json

000048,華夏雙債加強債券C,2019-03-26,1.2230,1.2236,0.05,2019-03-27 15:00api

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:00dom

000016,華夏純債債券C,2019-03-26,1.1790,1.1793,0.03,2019-03-27 15:00

功能截圖

配置說明

# 確保安裝如下庫,若是沒有,請在python3環境下執行pip install 模塊名
    import requests
    import random
    import re
    import queue
    import threading
    import csv
    import json

補充

完整版源代碼存放在github上,有須要的能夠下載

項目持續更新,歡迎您star本項目

相關文章
相關標籤/搜索