python爬虫——增量式爬虫——queue

python队列Queue

Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个使用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递。

基本FIFO队列

class Queue.Queue(maxsize=0)。FIFO即first in first out,先进先出。queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。它是进行广度遍历。

import queue
test = queue.Queue()
test.put("123")
print(test.get())
test.get()

然后python会一直运行。

LIFO队列

LIFO即Last in First Out,后进先出。与栈的类似,使用同FIFO用法类似。

如果要实现增量式爬虫,要使用FIFO队列

以爬百度贴吧为例:

import requests
import lxml.html
from queue import Queue


class TiebaSpider(object):
    """
    实现下载某个贴吧指定页码前的内容,存储下载内容
    """

    def __init__(self, name, pages):
        """
        初始化方法
        """
        self.tieba_name = name
        self.pages_download = pages
        self.base_url = "https://tieba.baidu.com/f?kw={}&ie=utf-8&pn={}"
        self.header = {"User-Agent": "Python"}

        self.crawl_queue = Queue()
        self.crawl_queue.put(UrlType(0, "https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=0"))

    def make_url_list(self):
        """
        获取待下载的url列表
        :return:返回生成的url列表
        """
        url_lists = []
        for i in range(self.pages_download):
            download_url = self.base_url.format(self.tieba_name, i * 50)
            url_lists.append(download_url)
        return url_lists

    # 注意maybe static 警告,怎么消除警告?
    def save_url(self, content, file_name):
        """
        将指定内容进行存储
        :param content:要存储的内容,这里传入的参数要求是二进制
        :param file_name:文件名
        :return:无
        """
        with open(file_name, 'wb') as f:
            f.write(content)

    def download_url(self, url_str):
        """
        下载指定url处的内容
        :param url_str: 要下载的地址
        :return: 返回下载的结果
        """
        response = requests.get(url_str, headers=self.header)
        return response.text  # content是二进制数据

    def run(self):
        """
        主业务逻辑,使用run后期可以改造成多线程爬虫
        :return:
        """
        while not self.crawl_queue.empty():
            url_type = self.crawl_queue.get()
            # 广度优先遍历的访问自身
            print("正在下载", url_type.compelete_url())
            result_text = self.download_url(url_type.compelete_url())
            parse_result = lxml.html.fromstring(result_text)

            # 广度优先遍历的访问邻居
            if url_type.url_type == 1 or url_type.url_type == 0:
                result_elements = parse_result.cssselect("ul#thread_list > li.j_thread_list")
                next_element = parse_result.cssselect("div.thread_list_bottom a.next")[0]
                url_str_next = next_element.xpath(".//@href")[0]
                self.crawl_queue.put(UrlType(1, url_str_next))
                # print("next page is :",url_str_next)
                # print("*" * 50)

                for result_element in result_elements:
                    result_thread = result_element.cssselect("div.threadlist_title > a.j_th_tit")[0]
                    print(result_thread.text)
                    url_str_detail = result_thread.xpath(".//@href")[0]
                    self.crawl_queue.put(UrlType(2, url_str_detail))
                    print(url_str_detail)
            else:
                pass


class UrlType(object):
    """
    URL类型对象,用来存放网址类型
    """

    def __init__(self, url_type, url_str):
        """
        初始化函数
        :param url_type: url类型 1:下一页 2:详情页
        :param url_str: url字符串
        """
        self.url_type = url_type
        self.url_str = url_str

    def compelete_url(self):
        """
        根据url_type类型返回完整的url
        :return:
        """
        if self.url_type == 1:
            return "https:" + self.url_str

        if self.url_type == 2:
            return "https://tieba.baidu.com" + self.url_str

        return self.url_str


tieba_spider = TiebaSpider('lol', 2)
tieba_spider.run()

然后就会一直进行爬取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章