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之编写类之一创建实例
Oct 11 Python
python套接字流重定向实例汇总
Mar 03 Python
Python实现购物程序思路及代码
Jul 24 Python
Python回文字符串及回文数字判定功能示例
Mar 20 Python
Numpy中转置transpose、T和swapaxes的实例讲解
Apr 17 Python
centos6.8安装python3.7无法import _ssl的解决方法
Sep 17 Python
python 对类的成员函数开启线程的方法
Jan 22 Python
pytorch如何冻结某层参数的实现
Jan 10 Python
Python操作注册表详细步骤介绍
Feb 05 Python
pandas 像SQL一样使用WHERE IN查询条件说明
Jun 05 Python
python装饰器三种装饰模式的简单分析
Sep 04 Python
python pandas 解析(读取、写入)CSV 文件的操作方法
Dec 24 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
慎用preg_replace危险的/e修饰符(一句话后门常用)
2013/06/19 PHP
php数组随机排序实现方法
2015/06/13 PHP
Ubuntu server 11.04安装memcache及php使用memcache来存储session的方法
2016/05/31 PHP
PHP实现的解汉诺塔问题算法示例
2018/08/06 PHP
thinkphp5实现无限级分类
2019/02/18 PHP
php生成微信红包数组的方法
2019/09/05 PHP
Date对象格式化函数代码
2010/07/17 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
点击显示指定元素隐藏其他同辈元素的方法
2014/02/19 Javascript
给html超链接设置事件不使用href来完成跳
2014/04/20 Javascript
vue2 mint-ui loadmore实现下拉刷新,上拉更多功能
2018/03/21 Javascript
vue 父组件给子组件传值子组件给父组件传值的实例代码
2019/04/15 Javascript
详解微信小程序图片地扯转base64解决方案
2019/08/18 Javascript
[13:18]《一刀刀一天》之DOTA全时刻21:详解TI新赛制 A队再露獠牙
2014/06/24 DOTA
pycharm 使用心得(四)显示行号
2014/06/05 Python
Python 实现删除某路径下文件及文件夹的实例讲解
2018/04/24 Python
关于python2 csv写入空白行的问题
2018/06/22 Python
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
python 判断文件还是文件夹的简单实例
2019/06/10 Python
Django media static外部访问Django中的图片设置教程
2020/04/07 Python
python根据字典的键来删除元素的方法
2020/08/16 Python
尤为Wconcept中国官网:韩国设计师品牌服饰
2019/01/10 全球购物
应届生幼儿园求职信
2013/11/12 职场文书
会计自荐书
2013/12/02 职场文书
社区八一活动方案
2014/02/03 职场文书
工地安全检查制度
2014/02/04 职场文书
自行车广告词大全
2014/03/21 职场文书
小学生爱国演讲稿
2014/04/25 职场文书
公益广告标语
2014/06/19 职场文书
国家奖学金获奖感言
2014/08/16 职场文书
2014年商场工作总结
2014/11/22 职场文书
本科毕业论文指导教师评语
2014/12/30 职场文书
生日宴会家属答谢词
2015/09/29 职场文书
小学秋季运动会通讯稿
2015/11/25 职场文书
mysql 带多个条件的查询方式
2021/06/05 MySQL
梳理总结Python开发中需要摒弃的18个坏习惯
2022/01/22 Python