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 相关文章推荐
在windows下快速搭建web.py开发框架方法
Apr 22 Python
Python第三方库的安装方法总结
Jun 06 Python
Python实现MySQL操作的方法小结【安装,连接,增删改查等】
Jul 12 Python
python机器学习理论与实战(一)K近邻法
Jan 28 Python
Python3实现的字典、列表和json对象互转功能示例
May 22 Python
利用anaconda保证64位和32位的python共存
Mar 09 Python
使用Python做垃圾分类的原理及实例代码附源码
Jul 02 Python
python django下载大的csv文件实现方法分析
Jul 19 Python
pytorch使用指定GPU训练的实例
Aug 19 Python
解决python 文本过滤和清理问题
Aug 28 Python
django框架中ajax的使用及避开CSRF 验证的方式详解
Dec 11 Python
解决tensorflow由于未初始化变量而导致的错误问题
Jan 06 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使用array_fill定义多维数组的方法
2015/03/18 PHP
php版微信公众平台之微信网页登陆授权示例
2016/09/23 PHP
AeroWindow 基于JQuery的弹出窗口插件
2011/06/27 Javascript
常规表格多表头查询示例
2014/02/21 Javascript
jquery判断浏览器后退时候弹出消息的方法
2014/08/11 Javascript
js实现横向百叶窗效果网页切换动画效果的方法
2015/03/02 Javascript
JavaScript中操作Mysql数据库实例
2015/04/02 Javascript
Bootstrap的图片轮播示例代码
2015/08/31 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
2016/05/21 Javascript
jQuery实现页面评论栏中访客信息自动填写功能的方法
2016/05/23 Javascript
jQuery根据ID、CLASS、等获取对象的实例
2016/12/04 Javascript
AngularJS入门教程二:在路由中传递参数的方法分析
2017/05/27 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
js实现canvas图片与img图片的相互转换的示例
2017/08/31 Javascript
vue中使用vue-router切换页面时滚动条自动滚动到顶部的方法
2017/11/28 Javascript
jQuery实现简单的下拉菜单导航功能示例
2017/12/07 jQuery
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
[43:58]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第一场 1月8日
2021/03/11 DOTA
python3中int(整型)的使用教程
2017/03/23 Python
python爬取个性签名的方法
2018/06/17 Python
python添加模块搜索路径和包的导入方法
2019/01/19 Python
详解python配置虚拟环境
2019/04/08 Python
详解用Python实现自动化监控远程服务器
2019/05/18 Python
爬虫代理的cookie如何生成运行
2020/09/22 Python
PyCharm Ctrl+Shift+F 失灵的简单有效解决操作
2021/01/15 Python
突破canvas语法限制 让他支持链式语法
2012/12/24 HTML / CSS
企业行政文员岗位职责
2013/12/03 职场文书
淘宝中秋节活动方案
2014/01/31 职场文书
会计专业自我鉴定
2014/02/10 职场文书
市场营销管理毕业生自荐信
2014/03/03 职场文书
南京青奥会口号
2014/06/12 职场文书
2014领导干部四风问题查摆思想汇报
2014/09/13 职场文书
我的大学四年规划书范文2014
2014/09/26 职场文书
教师思想工作总结2015
2015/05/13 职场文书
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android
美国运营商 T-Mobile 以 117.83Mb/s 的速度排第一位
2022/04/21 数码科技