爬虫之多线程

1.引入

之前写的爬虫都是单个线程的,一旦某个地方卡住不动了,那就要演员等待下去了,所以我们可以使用多线程或多进程来处理

但是我个人不建议用,不过 还是简单的介绍下

2.使用

爬虫使用多线程来处理网络请求,使用线程来处理URL队列中的url,然后将url返回的结果保存在另一个队列中,其它线程在读取这个队列中的数据,然后写到文件中去

3. 主要组成部分

3.1 URL队列和结果队列

将要爬取的url放在一个队列中,这里使用标准库Queue,访问url后的结果保存在结果队列中

初始化一个URL队列

from queue import Queue
url_queue=Queue()
html_queue=Queue()
3.2 请求线程

使用多个线程,不停的取URL队列中的url,并进行处理:

from threading import Thread
class ThreadInfo(Thread):
    def __init__(self,url_queue,html_queue):
        Thread.__init__(self)
        self.url_queue=url_queue
        self.html_queue=html_queue
    def run(self):
        user_agents = [
            "User-Agent:Mozilla/5.0(Windows;U;WindowsNT6.1;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50",
            "User-Agent:Mozilla/5.0(WindowsNT6.1;rv:2.0.1)Gecko/20100101Firefox/4.0.1",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
        ]
        headers = {
            "User-Agent": choice(user_agents)
        }
        while self.url_queue.empty()==False:
            url=self.url_queue.get()
            response = requests.get(url,headers=headers)
            if response.status_code==200:
                self.html_queue.put(response.text)

如果队列为空,线程就会被阻塞,知道队列不为空,处理队列中的一条数据后,就需要通知队列已经这条数据处理完

3.3 处理线程

处理结果队列中的数据,并保存到文件中,如果使用多个线程的话必须要给文件加上锁

lock=threading.Lock()
f=codecs.open('xiaohua.txt','w','utf-8')

当线程需要写入文件的时候,可以这样处理:

with lock:
	f.write(something)

4. 一个小例子

这里举一个爬取糗事百科的段子的例子,

from threading import Thread
from queue import Queue
from lxml import etree
from random import choice
import requests

#爬虫类
class CrawlInfo(Thread):
    def __init__(self,url_queue,html_queue):
        Thread.__init__(self)
        self.url_queue=url_queue
        self.html_queue=html_queue
    def run(self):
        user_agents = [
            "User-Agent:Mozilla/5.0(Windows;U;WindowsNT6.1;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50",
            "User-Agent:Mozilla/5.0(WindowsNT6.1;rv:2.0.1)Gecko/20100101Firefox/4.0.1",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
        ]
        headers = {
            "User-Agent": choice(user_agents)
        }
        while self.url_queue.empty()==False:#url队列不为空的时候
            url=self.url_queue.get()
            response = requests.get(url,headers=headers)
            if response.status_code==200:
                self.html_queue.put(response.text)

#解析类
class ParseInfo(Thread):
    def __init__(self,html_queue):
        Thread.__init__(self)
        self.html_queue=html_queue
    def run(self):
        while self.html_queue.empty()==False:
            e = etree.HTML(self.html_queue.get())
            span_list=e.xpath('//div[@class="content"]/span[1]')
            with open('xiaohua.txt','a',encoding='utf-8') as f:
                for span in span_list:
                    info=span.xpath('string(.)')
                    f.write(info+'\n')
if __name__=='__main__':
    url_queue=Queue()#用来存储url的容器
    base_url="https://www.qiushibaike.com/text/page/{}/"
    html_queue=Queue()#用来存储爬取到的整个页面的html,还未解析
    for i in range(1,14):
        new_url=base_url.format(i)
        print(new_url)
        url_queue.put(new_url)

    Crawl_list=[]#用来放爬虫类的线程,因为下面要让3个线程都等待,所以需要存起来
    for i in range(0,3):#创建3个线程
        Crawl1=CrawlInfo(url_queue,html_queue)
        Crawl_list.append(Crawl1)
        Crawl1.start()

    for crawl in Crawl_list:
        crawl.join()

    parse_list=[]
    for i in range(0,3):

        parse=ParseInfo(html_queue)
        parse_list.append(parse)
        parse.start()
    for parse in parse_list:
        parse.join()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值