import requests
import json
from retrying import retry
from lxml import etree
from queue import Queue
import threading

class QiuShi:
  def __init__(self):
    # 定义三个队列
    self.url_queue = Queue()
    self.html_queue = Queue()
    self.content_list_queue = Queue()
    self.headers = {
    "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
    }

  def get_url_list(self):
    url_list = ['https://www.qiushibaike.com/8hr/page/{}/'.format(i) for i in range(1, 14)]
    for url in url_list:
      # 将url使用put方法放入队列
      self.url_queue.put(url)

  @retry(stop_max_attempt_number=3)
  def _parse_url(self, url):
    response = requests.get(url, headers=self.headers, timeout=3)
    assert response.status_code == 200
    return etree.HTML(response.content)

  def parse_url(self):
  # 这里需要一个url。
  # 因为url = self.url_queue.get()只会从队列里取一次url.所以这里需要加while True循环来取。
  # 当url队列里没有url的时候这里会堵塞等待,只要有就取。
  # 但是取过后队列的基数并没有减1(并没有减去刚取走的url),所以要在下面使用task_done()
  while True:
    url = self.url_queue.get()
    print(url)
    try:
      html = self._parse_url(url)
    except:
      html = None
    # 将html添加到队列里
    self.html_queue.put(html)
    self.url_queue.task_done()

  def get_content_list(self):
    # 和上面一样
    while True:
      html = self.html_queue.get()
      if html is not None:
        div_list = html.xpath('//div[@id="content-left"]/div')
        content_list = []
        for div in div_list:
          item = {}
          item['name'] = div.xpath('.//h2/text()')[0].replace("\n", "") if len(div.xpath('.//h2/text()')) > 0 else None
          item['content'] = div.xpath('.//div[@class="content"]/span/text()')[0].replace("\n", "") if len(div.xpath('.//div[@class="content"]/span/text()')) > 0 else None
          item['comment'] = div.xpath('.//i[@class="number"]/text()')[1] if len(div.xpath('.//i[@class="number"]/text()')) > 0 else None
          item['img'] = div.xpath('.//img/@src') if len(div.xpath('.//img/@src')) > 0 else None

          content_list.append(item)
         self.content_list_queue.put(content_list)
      self.html_queue.task_done()

  def save_content_list(self):
    while True:
      content_list = self.content_list_queue.get()

      with open("qiubai.json", "a", encoding="utf-8") as f:
        for content in content_list:
          json.dump(content, f, ensure_ascii=False, indent=2)
          f.write(',\n')

      self.content_list_queue.task_done()

  def run(self):
    thread_list = []
    # 创建一个提取url的线程
    t_url = threading.Thread(target=self.get_url_list)
    thread_list.append(t_url)
    # 因为发送请求比较耗时,这里我们就用多线程来做
    for i in range(5):
      t_parse = threading.Thread(target=self.parse_url)
      thread_list.append(t_parse)
    # 提取数据也比较耗时,这里我们也使用多线程
    for i in range(3):
      t_get_content_list = threading.Thread(target=self.get_content_list)
      thread_list.append(t_get_content_list)
    # 保存数据必须用一个线程要数据就会乱
    t_save = threading.Thread(target=self.save_content_list)
    thread_list.append(t_save)
    for t in thread_list:
      t.setDaemon(True) # 守护线程
      t.start()
    # 当所有队列里没有数据,基数都等于0的时候主线程结束。否则一直堵塞在q.join()
    for q in [self.content_list_queue, self.html_queue, self.url_queue]:
      q.join()

if __name__ == '__main__':
qiubai = QiuShi()
qiubai.run()

python3 多线程获取数据实例的更多相关文章

  1. PHP中使用CURL模拟登录并获取数据实例

    cURL 是一个功能强大的PHP库,使用PHP的cURL库可以简单和有效地抓取网页并采集内容,设置cookie完成模拟登录网页,curl提供了丰富的函数,开发者可以从PHP手册中获取更多关于cURL信 ...

  2. ios 异步多线程 获取数据

    简介 iOS有三种多线程编程的技术,分别是: (一)NSThread  (二)Cocoa NSOperation (三)GCD(全称:Grand Central Dispatch)   这三种编程方式 ...

  3. HBase 高性能获取数据(多线程批量式解决办法) + MySQL和HBase性能测试比较

    摘要:   在前篇博客里已经讲述了通过一个自定义 HBase Filter来获取数据的办法,在末尾指出此办法的性能是不能满足应用要求的,很显然对于如此成熟的HBase来说,高性能获取数据应该不是问题. ...

  4. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  5. Datatables插件1.10.15版本服务器处理模式ajax获取分页数据实例解析

    一.问题描述 前端需要使用表格来展示数据,找了一些插件,最后确定使用dataTables组件来做. 后端的分页接口已经写好了,不能修改.接口需要传入页码(pageNumber)和页面显示数据条数(pa ...

  6. 第五章 “我要点爆”微信小程序云开发实例之从云端获取数据制作首页

    下面我们来实现从云端获取数据,完成首页世界页面index的制作,首页分为4个数据列表导航页面,页面具体内容如下: 推荐:为用户推荐最新的点爆信息,它包含文本点爆内容和语音点爆内容. 文爆:筛选出文字点 ...

  7. Java获取http和https网址对应html数据实例

    由于之前在公司一直用的C#做的软件开发,近些天有同学需要用Java做一个从指定网址获取信息的Java程序.正好不是很难,顺便复习了一下Java的知识. 要求如下,在https://www.marine ...

  8. python3实践-从网站获取数据(Carbon Market Data-BJ) (pandas,bs4)

    自己边看边实践一些简单的实际应用,下面的程序是从某个网站上获取需要的数据. 在编写的过程中,通过学习陆续了解到一些方法,发现Python真的是很便捷. 尤其是用pandas获取网页中的表格数据,真的是 ...

  9. BlockingQueue阻塞队列(解决多线程中数据安全问题 可用于抢票,秒杀)

    案例:一个线程类中 private static BlockingQueue<Map<String, String>> dataQueue = new LinkedBlocki ...

随机推荐

  1. javascript中DOM集锦(二)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. SQLserver2008r2安装过程

    首先,下载SQLserver2008的安装包,下载完成打开是以下界面 点击开始安装,随着安装进程,点下一步 . 接着来到设置角色的过程,点击SQL功能安装 然后按下一步,来到功能选择,点击" ...

  3. Vue的条件渲染

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. IDL 使用数组

    1.下标方式 IDL> array=indgen(8) IDL> print,array 0 1 2 3 4 5 6 7 IDL> print,array[3] IDL> ar ...

  5. java自动化测试-http请求get

    首先我10.1过来自己玩通了讨鬼转极,看了电视剧白夜追凶,换了工作小组,这段时间确实比较少的更新博客,确实有点不勤奋,我先自我检讨 我就不赘述java的安装了,这个是比较简单的,有必要的话以后在讲 对 ...

  6. 逆波兰表达式(RPN)算法简单实现

    算法分析: 一.预处理 给定任意四则运算的字符串表达式(中缀表达式),preDeal预先转化为对应的字符串数组,其目的在于将操作数和运算符分离. 例如给定四则运算内的中缀表达式: String inf ...

  7. 4.ElasticSearch的基本api操作

    1. ElasticSearch的Index 1. 索引初始化 在创建索引之前 对索引进行初始化操作 指定shards数量和replicas数量 curl -XPUT 'http://192.168. ...

  8. Unity 使用 陀螺仪 实现 《王者荣耀》 登入界面 背景动态效果

    在 <王者荣耀> 登入界面 左右上下晃动手机(有些手机不支持)可以看到背景在变化 我使用的是iPhone SE 效果如下: 对比两张图片的左下角 可以看到差异 至于为什么要这么做: 1.使 ...

  9. python 基础大纲

    机器语言: 特点:计算机能够看懂的0和1去写程序 优点:程序运行速度快 缺点:开发效率低 汇编语言: 特点:用一些英文标签代替一串而精致数字去写程序 优点:比机器语言好一点,操作系统内大量使用汇编语言 ...

  10. popup方法

    popup方法: 一.创建一个页面 1.创建url和视图函数:: from django.shortcuts import render def p1(request): return render( ...