Python如何使用队列方式实现多线程爬虫


Posted in Python onMay 12, 2020

说明:糗事百科段子的爬取,采用了队列和多线程的方式,其中关键点是Queue.task_done()、Queue.join(),保证了线程的有序进行。

代码如下

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

class Qsbk(object):
  def __init__(self):
    self.headers = {
      "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
      "Referer": "https://www.qiushibaike.com/"
    }
    # 实例化三个队列,用来存放内容
    self.url_queue = Queue()
    self.html_queue = Queue()
    self.content_queue = Queue()

  def get_total_url(self):
    """
    获取了所有的页面url,并且返回url_list
    return:url_list
    现在放入url_queue队列中保存
    """
    url_temp = "https://www.qiushibaike.com/text/page/{}/"
    url_list = list()
    for i in range(1,13):
      # url_list.append(url_temp.format(i))
      # 将生成的url放入url_queue队列
      self.url_queue.put(url_temp.format(i))

  def parse_url(self):
    """
    发送请求,获取响应,同时etree处理html
    """
    while self.url_queue.not_empty:
      # 判断非空,为空时结束循环

      # 从队列中取出一个url
      url = self.url_queue.get()
      print("parsing url:",url)
      # 发送请求
      response = requests.get(url,headers=self.headers,timeout=10)
      # 获取html字符串
      html = response.content.decode()
      # 获取element类型的html
      html = etree.HTML(html)
      # 将生成的element对象放入html_queue队列
      self.html_queue.put(html)
      # Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
      self.url_queue.task_done()

  def get_content(self):
    """
    解析网页内容,获取想要的信息
    """
    while self.html_queue.not_empty:
      items = list()
      html = self.html_queue.get()
      total_div = html.xpath("//div[@class='col1 old-style-col1']/div")
      for i in total_div:

        author_img = i.xpath(".//a[@rel='nofollow']/img/@src")
        author_img = "https"+author_img[0] if len(author_img)>0 else None

        author_name = i.xpath(".//a[@rel='nofollow']/img/@alt")
        author_name = author_name[0] if len(author_name)>0 else None

        author_href = i.xpath("./a/@href")
        author_href = "https://www.qiushibaike.com/"+author_href[0] if len(author_href)>0 else None

        author_gender = i.xpath("./div[1]/div/@class")
        author_gender = author_gender[0].split(" ")[-1].replace("Icon","").strip() if len(author_gender)>0 else None

        author_age = i.xpath("./div[1]/div/text()")
        author_age = author_age[0] if len(author_age)>0 else None

        content = i.xpath("./a/div/span/text()")
        content = content[0].strip() if len(content)>0 else None

        content_vote = i.xpath("./div[@class='stats']/span[@class='stats-vote']/i/text()")
        content_vote = content_vote[0] if len(content_vote)>0 else None

        content_comment_numbers = i.xpath("./div[@class='stats']/span[@class='stats-comments']/a/i/text()")
        content_comment_numbers = content_comment_numbers[0] if len(content_comment_numbers)>0 else None

        item = {
          "author_name":author_name,
          "author_age" :author_age,
          "author_gender":author_gender,
          "author_img":author_img,
          "author_href":author_href,
          "content":content,
          "content_vote":content_vote,
          "content_comment_numbers":content_comment_numbers,
        }
        items.append(item)
      self.content_queue.put(items)
      # task_done的时候,队列计数减一
      self.html_queue.task_done()

  def save_items(self):
    """
    保存items
    """
    while self.content_queue.not_empty:
      items = self.content_queue.get()
      with open("quishibaike.txt",'a',encoding='utf-8') as f:
        for i in items:
          json.dump(i,f,ensure_ascii=False,indent=2)
      self.content_queue.task_done()

  def run(self):
    # 获取url list
    thread_list = list()
    thread_url = threading.Thread(target=self.get_total_url)
    thread_list.append(thread_url)

    # 发送网络请求
    for i in range(10):
      thread_parse = threading.Thread(target=self.parse_url)
      thread_list.append(thread_parse)

    # 提取数据
    thread_get_content = threading.Thread(target=self.get_content)
    thread_list.append(thread_get_content)

    # 保存
    thread_save = threading.Thread(target=self.save_items)
    thread_list.append(thread_save)


    for t in thread_list:
      # 为每个进程设置为后台进程,效果是主进程退出子进程也会退出
      t.setDaemon(True)
      t.start()
    
    # 让主线程等待,所有的队列为空的时候才能退出
    self.url_queue.join()
    self.html_queue.join()
    self.content_queue.join()


if __name__=="__main__":
  obj = Qsbk()
  obj.run()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 测试实现方法
Dec 24 Python
python使用win32com在百度空间插入html元素示例
Feb 20 Python
python实现矩阵乘法的方法
Jun 28 Python
详解Django通用视图中的函数包装
Jul 21 Python
浅谈Python peewee 使用经验
Oct 20 Python
Windows下安装Scrapy
Oct 17 Python
python3 中文乱码与默认编码格式设定方法
Oct 31 Python
python 格式化输出百分号的方法
Jan 20 Python
python实现图片压缩代码实例
Aug 12 Python
python读取Excel表格文件的方法
Sep 02 Python
python自动化测试三部曲之unittest框架的实现
Oct 07 Python
python调用ffmpeg命令行工具便捷操作视频示例实现过程
Nov 01 Python
python的Jenkins接口调用方式
May 12 #Python
jenkins+python自动化测试持续集成教程
May 12 #Python
python百行代码自制电脑端网速悬浮窗的实现
May 12 #Python
基于Python的Jenkins的二次开发操作
May 12 #Python
Python-jenkins模块获取jobs的执行状态操作
May 12 #Python
Python-jenkins 获取job构建信息方式
May 12 #Python
python进行参数传递的方法
May 12 #Python
You might like
PHP的autoload自动加载机制使用说明
2010/12/28 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
PHP实现批量删除(封装)
2017/04/28 PHP
javascript 文章截取部分无损html显示实现代码
2010/05/04 Javascript
最常用的12种设计模式小结
2011/08/09 Javascript
如何创建一个JavaScript弹出DIV窗口层的效果
2013/09/25 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
2014/03/25 Javascript
基于jQuery实现select下拉选择可输入附源码下载
2016/02/03 Javascript
对Js OOP编程 创建对象的一些全面理解
2016/07/26 Javascript
xtemplate node.js 的使用方法实例解析
2016/08/22 Javascript
Vee-Validate的使用方法详解
2017/09/22 Javascript
AngularJS遍历获取数组元素的方法示例
2017/11/11 Javascript
javascript用rem来做响应式开发
2018/01/13 Javascript
ES6入门教程之变量的解构赋值详解
2019/04/13 Javascript
vue移动端城市三级联动组件使用详解
2019/07/26 Javascript
Vue.js组件使用props传递数据的方法
2019/10/19 Javascript
js函数和this用法实例分析
2020/03/13 Javascript
JS禁用右键、禁用Ctrl+u、禁用Ctrl+s、禁用F12的实现代码
2020/12/01 Javascript
python中使用百度音乐搜索的api下载指定歌曲的lrc歌词
2014/07/18 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
修改python plot折线图的坐标轴刻度方法
2018/12/13 Python
python数据预处理之数据标准化的几种处理方式
2019/07/17 Python
python随机数分布random均匀分布实例
2019/11/27 Python
flask 使用 flask_apscheduler 做定时循环任务的实现
2019/12/10 Python
关于pycharm 切换 python3.9 报错 ‘HTMLParser‘ object has no attribute ‘unescape‘ 的问题
2020/11/24 Python
Python 调用C++封装的进一步探索交流
2021/03/04 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
Zooplus葡萄牙:欧洲领先的网上宠物商店
2018/07/01 全球购物
Spartoo荷兰:鞋子、包包和服装
2018/07/12 全球购物
爱护公物演讲稿
2014/09/09 职场文书
停车位租赁协议书
2014/09/24 职场文书
鲁滨孙漂流记读书笔记
2015/06/30 职场文书
2016高考冲刺决心书
2015/09/23 职场文书
详解如何在Canvas中添加事件的方法
2021/04/17 Javascript
mysql连接查询中and与where的区别浅析
2021/07/01 MySQL
Python中time标准库的使用教程
2022/04/13 Python