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生成随机mac地址的方法
Mar 16 Python
Python 正则表达式入门(中级篇)
Dec 07 Python
基于使用paramiko执行远程linux主机命令(详解)
Oct 16 Python
Python实现扣除个人税后的工资计算器示例
Mar 26 Python
对python:print打印时加u的含义详解
Dec 15 Python
python中yield的用法详解——最简单,最清晰的解释
Apr 04 Python
python  文件的基本操作 菜中菜功能的实例代码
Jul 17 Python
python对常见数据类型的遍历解析
Aug 27 Python
Python之Numpy的超实用基础详细教程
Oct 23 Python
python爬虫开发之使用Python爬虫库requests多线程抓取猫眼电影TOP100实例
Mar 10 Python
如何基于线程池提升request模块效率
Apr 18 Python
关于matplotlib-legend 位置属性 loc 使用说明
May 16 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跳出循环的方法以及continue、break、exit的区别介绍
2013/07/01 PHP
php统计文章排行示例
2014/03/04 PHP
在PHP模板引擎smarty生成随机数的方法和math函数详解
2014/04/24 PHP
PHP实现在线阅读PDF文件的方法
2015/06/23 PHP
Yii框架结合sphinx,Ajax实现搜索分页功能示例
2016/10/18 PHP
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
js打开新窗口方法整理
2014/02/17 Javascript
jquery attr()设置和获取属性值实例教程
2016/09/25 Javascript
nodejs基础应用
2017/02/03 NodeJs
微信小程序搜索组件wxSearch实例详解
2017/06/08 Javascript
浅谈angular4生命周期钩子
2017/09/05 Javascript
JavaScript实现计算多边形质心的方法示例
2018/01/31 Javascript
JS实现获取word文档内容并输出显示到html页面示例
2018/06/23 Javascript
vue中使用axios post上传头像/图片并实时显示到页面的方法
2018/09/27 Javascript
小程序实现列表点赞功能
2018/11/02 Javascript
微信小程序sessionid不一致问题解决
2019/08/30 Javascript
vue配置nprogress实现页面顶部进度条
2019/09/21 Javascript
vue-router的钩子函数用法实例分析
2019/10/26 Javascript
如何基于js判断浏览器版本
2020/02/20 Javascript
Python 专题三 字符串的基础知识
2017/03/19 Python
python使用xslt提取网页数据的方法
2018/02/23 Python
Django开发的简易留言板案例详解
2018/12/04 Python
Python数据类型之列表和元组的方法实例详解
2019/07/08 Python
python pandas获取csv指定行 列的操作方法
2019/07/12 Python
python自动结束mysql慢查询会话的实例代码
2019/10/27 Python
基于PyQT实现区分左键双击和单击
2020/05/19 Python
Keras:Unet网络实现多类语义分割方式
2020/06/11 Python
python+django+selenium搭建简易自动化测试
2020/08/19 Python
Pandas之缺失数据的实现
2021/01/06 Python
python利用appium实现手机APP自动化的示例
2021/01/26 Python
CSS3解决移动页面上点击链接触发色块的问题
2016/06/03 HTML / CSS
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
Under Armour安德玛英国官网:美国高端运动科技品牌
2018/09/17 全球购物
应届大学生自荐信格式
2013/09/21 职场文书
学术会议领导致辞
2015/07/29 职场文书
Win10 Anaconda安装python-pcl
2022/04/29 Servers