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 相关文章推荐
使用相同的Apache实例来运行Django和Media文件
Jul 22 Python
初步认识Python中的列表与位运算符
Oct 12 Python
学习python之编写简单简单连接数据库并执行查询操作
Feb 27 Python
Python使用ConfigParser模块操作配置文件的方法
Jun 29 Python
详解Python下Flask-ApScheduler快速指南
Nov 04 Python
python定时检测无响应进程并重启的实例代码
Apr 22 Python
python多线程扫描端口(线程池)
Sep 04 Python
Python tcp传输代码实例解析
Mar 18 Python
python如何判断IP地址合法性
Apr 05 Python
详细分析Python垃圾回收机制
Jul 01 Python
Python切片列表字符串如何实现切换
Aug 06 Python
python定时截屏实现
Nov 02 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
PHILIPS L4X25T电路分析和打理
2021/03/02 无线电
php Notice: Undefined index 错误提示解决方法
2010/08/29 PHP
使用PHP导出Redis数据到另一个Redis中的代码
2014/03/12 PHP
php短址转换实现方法
2015/02/25 PHP
php微信公众号开发之二级菜单
2018/10/20 PHP
javascript 放大镜 v1.0 基于Yui2 实现的放大镜效果
2010/03/08 Javascript
面向对象的Javascript之二(接口实现介绍)
2012/01/27 Javascript
基于jquery的图片轮播 tab切换组件
2012/07/19 Javascript
JavaScript实现url地址自动检测并添加URL链接示例代码
2013/11/12 Javascript
使用jquery.qrcode生成彩色二维码实例
2014/08/08 Javascript
javascript实现在线客服效果
2015/07/15 Javascript
jQuery通过ajax方法获取json数据不执行success的原因及解决方法
2016/10/15 Javascript
javascript 操作cookies详解及实例
2017/02/22 Javascript
简单实现vue验证码60秒倒计时功能
2017/10/11 Javascript
Javascript中从学习bind到实现bind的过程
2018/01/05 Javascript
JavaScript 有用的代码片段和 trick
2018/02/22 Javascript
vue 虚拟dom的patch源码分析
2018/03/01 Javascript
Vue2.0使用嵌套路由实现页面内容切换/公用一级菜单控制页面内容切换(推荐)
2019/05/08 Javascript
[00:12]DAC SOLO赛卫冕冠军 VG.Paparazi灬展现SOLO技巧
2018/04/06 DOTA
[01:03:56]Mineski vs TNC 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
python flask安装和命令详解
2019/04/02 Python
python文件操作的简单方法总结
2019/11/07 Python
django Layui界面点击弹出对话框并请求逻辑生成分页的动态表格实例
2020/05/12 Python
Python getattr()函数使用方法代码实例
2020/08/10 Python
HTML5中语义化 b 和 i 标签
2008/10/17 HTML / CSS
美国肌肉和力量商店:Muscle & Strength
2019/06/22 全球购物
NICKIS.com荷兰:设计师儿童时装
2020/01/08 全球购物
2014元旦晚会策划方案
2014/02/19 职场文书
五一口号
2014/06/19 职场文书
防汛通知
2015/04/25 职场文书
结婚当天新郎保证书
2015/05/08 职场文书
写给同事的离职感言
2015/08/04 职场文书
nginx网站服务如何配置防盗链(推荐)
2021/03/31 Servers
用几道面试题来看JavaScript执行机制
2021/04/30 Javascript
linux下导入、导出mysql数据库命令的实现方法
2021/05/26 MySQL
Vue实现动态查询规则生成组件
2021/05/27 Vue.js