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 参数列表中的self 显式不等于冗余
Dec 01 Python
python求众数问题实例
Sep 26 Python
Python实现打印螺旋矩阵功能的方法
Nov 21 Python
python获取程序执行文件路径的方法(推荐)
Apr 26 Python
使用Python进行QQ批量登录的实例代码
Jun 11 Python
3分钟学会一个Python小技巧
Nov 23 Python
Python使用pandas对数据进行差分运算的方法
Dec 22 Python
Python pandas DataFrame操作的实现代码
Jun 21 Python
pycharm修改file type方式
Nov 19 Python
利用Python制作动态排名图的实现代码
Apr 09 Python
python模拟点击玩游戏的实例讲解
Nov 26 Python
python的netCDF4批量处理NC格式文件的操作方法
Mar 21 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 网络开发详解之远程文件包含漏洞
2010/04/25 PHP
单点登录 Ucenter示例分析
2013/10/29 PHP
php解压文件代码实现php在线解压
2014/02/13 PHP
php使用MySQL保存session会话的方法
2015/06/26 PHP
微信获取用户地理位置信息的原理与步骤
2015/11/12 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
JavaScript实际应用:innerHTMl和确认提示的使用
2006/06/22 Javascript
一个无限级XML绑定跨框架菜单(For IE)
2007/01/27 Javascript
给html超链接设置事件不使用href来完成跳
2014/04/20 Javascript
在css加载完毕后自动判断页面是否加入css或js文件
2014/09/10 Javascript
Node.js node-schedule定时任务隔多少分钟执行一次的方法
2015/02/10 Javascript
JavaScript事件类型中UI事件详解
2016/01/14 Javascript
javascript基础知识
2016/06/07 Javascript
两种JavaScript的AES加密方式(可与Java相互加解密)
2016/08/02 Javascript
bootstrap 下拉多选框进行多选传值问题代码分析
2017/02/14 Javascript
微信小程序 UI与容器组件总结
2017/02/21 Javascript
Express+Nodejs 下的登录拦截实现代码
2017/07/01 NodeJs
聊聊那些使用前端Javascript实现的机器学习类库
2017/09/18 Javascript
AngularJS 前台分页实现的示例代码
2018/06/07 Javascript
vue 项目中使用Loading组件的示例代码
2018/08/31 Javascript
为什么说JavaScript预解释是一种毫无节操的机制详析
2018/11/18 Javascript
JavaScript遍历DOM元素的常见方式示例
2019/02/16 Javascript
vue实现简单的日历效果
2020/09/24 Javascript
快速对接payjq的个人微信支付接口过程解析
2019/08/15 Javascript
JS实现多功能计算器
2020/10/28 Javascript
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
Python使用Matplotlib实现雨点图动画效果的方法
2017/12/23 Python
Python3实现的字典、列表和json对象互转功能示例
2018/05/22 Python
pycharm远程linux开发和调试代码的方法
2018/07/17 Python
Python中extend和append的区别讲解
2019/01/24 Python
细说CSS3中的选择符
2008/10/17 HTML / CSS
HTML5图片预览实例分享
2014/06/04 HTML / CSS
致裁判员加油稿
2014/02/08 职场文书
城市精细化管理实施方案
2014/03/04 职场文书
经理岗位职责范本
2015/04/15 职场文书
PostGIS的安装与入门使用指南
2022/01/18 PostgreSQL