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元字符的用法实例解析
Jan 17 Python
Python实现统计给定列表中指定数字出现次数的方法
Apr 11 Python
基于Pandas读取csv文件Error的总结
Jun 15 Python
在Mac上删除自己安装的Python方法
Oct 29 Python
python 解决动态的定义变量名,并给其赋值的方法(大数据处理)
Nov 10 Python
Tensorflow实现神经网络拟合线性回归
Jul 19 Python
使用PYTHON解析Wireshark的PCAP文件方法
Jul 23 Python
初次部署django+gunicorn+nginx的方法步骤
Sep 11 Python
解决python中import文件夹下面py文件报错问题
Jun 01 Python
手把手教你将Flask应用封装成Docker服务的实现
Aug 19 Python
详解使用Python写一个向数据库填充数据的小工具(推荐)
Sep 11 Python
python re.match()用法相关示例
Jan 27 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
单位速度在实战中的运用
2020/03/04 星际争霸
Laravel 关联模型-关联新增和关联更新的方法
2019/10/10 PHP
javascript开发中因空格引发的错误
2010/11/08 Javascript
Jquery对数组的操作技巧整理
2014/03/25 Javascript
JS 使用for循环遍历子节点查找元素
2014/09/06 Javascript
jQuery前端框架easyui使用Dialog时bug处理
2014/12/05 Javascript
jQuery中click事件的定义和用法
2014/12/20 Javascript
js超时调用setTimeout和间歇调用setInterval实例分析
2015/01/28 Javascript
JS获取月份最后天数、最大天数与某日周数的方法
2015/12/08 Javascript
JavaScript实现简洁的俄罗斯方块完整实例
2016/03/01 Javascript
AngularJS模板加载用法详解
2016/11/04 Javascript
jQuery checkbox选中问题之prop与attr注意点分析
2016/11/15 Javascript
layui前段框架日期控件使用方法详解
2017/05/19 Javascript
Angularjs的启动过程分析
2017/07/18 Javascript
vue 虚拟dom的patch源码分析
2018/03/01 Javascript
nuxt.js 缓存实践
2018/06/25 Javascript
基于layui实现高级搜索(筛选)功能
2019/07/26 Javascript
使用next.js开发网址缩短服务的方法
2020/06/17 Javascript
jQuery zTree如何改变指定节点文本样式
2020/10/16 jQuery
用Python实现协同过滤的教程
2015/04/08 Python
python命令行解析之parse_known_args()函数和parse_args()使用区别介绍
2018/01/24 Python
浅谈Python基础—判断和循环
2019/03/22 Python
python使用pygame模块实现坦克大战游戏
2020/03/25 Python
python 叠加等边三角形的绘制的实现
2019/08/14 Python
python将print输出的信息保留到日志文件中
2019/09/27 Python
利用pipenv和pyenv管理多个相互独立的Python虚拟开发环境
2020/11/01 Python
python 用struct模块解决黏包问题
2020/11/07 Python
用CSS3来实现社交分享按钮
2014/11/11 HTML / CSS
英国领先的大码时装品牌之一:Elvi
2018/08/26 全球购物
Java的五个基础面试题
2016/02/26 面试题
大一自我鉴定范文
2013/10/04 职场文书
军训的自我鉴定
2013/12/10 职场文书
满月酒答谢词
2014/01/14 职场文书
入党积极分子自我鉴定范文
2014/03/25 职场文书
爱之链教学反思
2014/04/30 职场文书
前端实现滑动按钮AJAX与后端交互的示例代码
2022/02/24 Javascript