python多线程+代理池爬取天天基金网、股票数据过程解析


Posted in Python onAugust 13, 2019

简介

提到爬虫,大部分人都会想到使用Scrapy工具,但是仅仅停留在会使用的阶段。为了增加对爬虫机制的理解,我们可以手动实现多线程的爬虫过程,同时,引入IP代理池进行基本的反爬操作。

本次使用天天基金网进行爬虫,该网站具有反爬机制,同时数量足够大,多线程效果较为明显。

技术路线

  • IP代理池
  • 多线程
  • 爬虫与反爬

编写思路

首先,开始分析天天基金网的一些数据。经过抓包分析,可知:
./fundcode_search.js包含所有基金的数据,同时,该地址具有反爬机制,多次访问将会失败的情况。

同时,经过分析可知某只基金的相关信息地址为:fundgz.1234567.com.cn/js/ + 基金代码 + .js

分析完天天基金网的数据后,搭建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']

搭建完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])

现在,开始编写如何获取指定基金的代码。首先,该函数必须先判断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("访问失败,尝试使用其他代理访问")

当访问成功时,则说明能够成功获得基金的相关数据。当我们在将这些数据存入到一个.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()

至此,大部分工作已经完成了。为了更好地实现伪装效果,我们对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)
  }

最后,在main中,开启线程即可。

# 创建一个线程锁,防止多线程写入文件时发生错乱
  mutex_lock = threading.Lock()
  # 线程数为50,在一定范围内,线程数越多,速度越快
  for i in range(50):
    t = threading.Thread(target=get_fund_data,name='LoopThread'+str(i))
    t.start()

通过对多线程和IP代理池的实践操作,能够更加深入了解多线程和爬虫的工作原理。当你在使用一些爬虫框架的时候,就能够做到快速定位错误并解决错误。

数据格式

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

功能截图

python多线程+代理池爬取天天基金网、股票数据过程解析

配置说明

# 确保安装以下库,如果没有,请在python3环境下执行pip install 模块名
  import requests
  import random
  import re
  import queue
  import threading
  import csv
  import json

补充

完整版源代码存放在github上,有需要的可以下载

项目持续更新,欢迎您star本项目

,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值

Python 相关文章推荐
初学python数组的处理代码
Jan 04 Python
python网络编程之UDP通信实例(含服务器端、客户端、UDP广播例子)
Apr 25 Python
Python ValueError: invalid literal for int() with base 10 实用解决方法
Jun 21 Python
简述Python中的进程、线程、协程
Mar 18 Python
Python使用dis模块把Python反编译为字节码的用法详解
Jun 14 Python
Python基于正则表达式实现文件内容替换的方法
Aug 30 Python
详解tensorflow训练自己的数据集实现CNN图像分类
Feb 07 Python
python3爬虫之设计签名小程序
Jun 19 Python
PyQt 实现使窗口中的元素跟随窗口大小的变化而变化
Jun 18 Python
Python作用域与名字空间原理详解
Mar 21 Python
python操作xlsx格式文件并读取
Jun 02 Python
python中sqllite插入numpy数组到数据库的实现方法
Jun 21 Python
Python字符串处理的8招秘籍(小结)
Aug 13 #Python
python实现批量修改服务器密码的方法
Aug 13 #Python
基于python分析你的上网行为 看看你平时上网都在干嘛
Aug 13 #Python
Python实现微信翻译机器人的方法
Aug 13 #Python
python读写csv文件的方法
Aug 13 #Python
python根据多个文件名批量查找文件
Aug 13 #Python
详解django实现自定义manage命令的扩展
Aug 13 #Python
You might like
关于PHP的相似度计算函数:levenshtein的使用介绍
2013/04/15 PHP
php实现使用正则将文本中的网址转换成链接标签
2014/12/03 PHP
详解WordPress中给链接添加查询字符串的方法
2015/12/18 PHP
Bootstrap+PHP实现多图上传功能实例详解
2018/04/08 PHP
详解PHP神奇又有用的Trait
2019/03/25 PHP
JavaScript动态创建div属性和样式示例代码
2013/10/09 Javascript
深入浅析JavaScript字符串操作方法 slice、substr、substring及其IE兼容性
2015/12/16 Javascript
原生javascript实现的ajax异步封装功能示例
2016/11/03 Javascript
一个简易时钟效果js实现代码
2020/03/25 Javascript
浅谈React中的元素、组件、实例和节点
2018/02/27 Javascript
vue router动态路由下让每个子路由都是独立组件的解决方案
2018/04/24 Javascript
对Vue- 动态元素属性及v-bind和v-model的区别详解
2018/08/27 Javascript
5分钟快速掌握JS中var、let和const的异同
2018/09/19 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
2018/09/21 Javascript
vue+高德地图写地图选址组件的方法
2019/05/18 Javascript
[02:47]2018年度DOTA2最佳辅助位选手4号位-完美盛典
2018/12/17 DOTA
浅谈Python peewee 使用经验
2017/10/20 Python
python中如何正确使用正则表达式的详细模式(Verbose mode expression)
2017/11/08 Python
python psutil库安装教程
2018/03/19 Python
Python实现求解一元二次方程的方法示例
2018/06/20 Python
numpy.linspace 生成等差数组的方法
2018/07/02 Python
通过实例了解Python异常处理机制底层实现
2020/07/23 Python
解决Python 写文件报错TypeError的问题
2020/10/23 Python
python3通过subprocess模块调用脚本并和脚本交互的操作
2020/12/05 Python
pycharm 的Structure界面设置操作
2021/02/05 Python
瑞典领先的汽车零部件网上零售商:bildelaronline24.se
2017/01/12 全球购物
九年级历史教学反思
2014/01/27 职场文书
党员大会主持词
2014/04/02 职场文书
高中教师考核方案
2014/05/18 职场文书
纪检监察建议书
2014/05/19 职场文书
化妆品活动策划方案
2014/05/23 职场文书
化工专业求职信
2014/07/01 职场文书
2014年小学国庆节活动方案
2014/09/16 职场文书
个人作风建设自查报告
2014/10/22 职场文书
导游词之青岛崂山
2019/12/27 职场文书
浅谈Redis主从复制以及主从复制原理
2021/05/29 Redis