爬虫--多线程编程-提高效率--泛见(犯贱)志趣图标题和链接爬取

#还需要调试 从头调试


import threading
import time
from queue import Queue
import requests
from lxml import etree
import json

#创建一个列表用来存放采集线程
g_crawl_list = []
#创建一个列表用来存放解析线程
g_parse_list = []


#创建采集线程对象  采集线程对象需要用到两个队列 页码的队列 存页面源码的队列
class CrawlThread(threading.Thread):
    def __init__(self,name,page_queue,data_queue):
        super().__init__()
        self.name = name
        self.page_queue = page_queue
        self.data_queue = data_queue
        self.url = "http://www.ifanjian.net/latest-{}"
        self.headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
    #启动采集线程后开始运行的函数
    def run(self):
        print('%s-----线程启动'% self.name)
        #线程要一直跑 要是不这样的话 他只能跑你创建的个数页
        while 1:
            #判断采集线程何时退出  要爬取的页数队列空了就结束了
            if self.page_queue.empty():
                break
            #从队列中取出页码
            page = self.page_queue.get()
            # print(page)
            # exit()
            #拼接url 发送请求
            url = self.url.format(page)
            # print(url)
            # exit()
            r = requests.get(url=url,headers = self.headers)
            # print(r.text)
            # exit()
            #将响应内容存放到data_queue队列中
            self.data_queue.put(r.text)
        print('%s-----线程结束'% self.name)



#创建解析线程对象   解析线程只需要页面源码这个队列 解析出的东西存入别的列表 最后输出
class ParserThread(threading.Thread):
    def __init__(self,name,data_queue,fp,lock):
        super().__init__()
        self.name = name
        self.data_queue = data_queue
        self.fp = fp
        self.lock = lock
    def run(self):
        print('%s-----线程启动'% self.name)
        while 1:
            # if self.data_queue.empty():
            #     break
            #从data_queue中取出一页数据
            data = self.data_queue.get()
            # print(data)
            # exit()
            #解析内容即可
            self.parse_content(data)
        print('%s-----线程结束'% self.name)
    def parse_content(self,data):
        tree = etree.HTML(data)
        #先查找所有的li再从li里面找自己的标题和url
        li_list = tree.xpath('//ul[@class = "cont-list"]/li')
        # print(li_list)
        # print(len(li_list))
        # exit()
        ##建立一个空列表存数据
        #items = []
        for oli in li_list:
            #获取图片标题
            title = oli.xpath('.//h2/a/text()')[0]
            # print(title)
            # exit()
            #获取图片url
            image_url = oli.xpath('.//div[contains(@class,"cont-list-main")]/p/img[@class= "lazy"]/@data-src')
            # print(image_url)
            # exit()
            #存放到一个字典中
            item = {
                '标题':title,
                '链接':image_url
            }
            # print(item)
            # exit()
            #写到文件中  但是需要先上锁
            self.lock.acquire()
            self.fp.write(str(item)+'
')
            self.lock.release()


#创建采集线程  就是实例化采集线程对象的函数
def create_crawl_thread(page_queue,data_queue):
    crawl_name = ['采集线程一号','采集线程二号','采集线程三号']
    for name in crawl_name:
        tcrawl = CrawlThread(name,page_queue,data_queue)
        #每次线程工作完一次把结果存放到采集列表
        g_crawl_list.append(tcrawl)


#创建解析线程  就是实例化解析线程对象的函数
def create_parse_thread(data_queue,fp,lock):
    parse_name = ['解析线程一号','解析线程二号','解析线程三号']
    for name in parse_name:
        tparse = ParserThread(name,data_queue,fp,lock)
        #每次线程工作完一次把结果存放到解析列表
        g_parse_list.append(tparse)

#创建队列函数
def create_queue():
    #创建页码队列
    page_queue = Queue()
    #这里添加爬取页数  目前是1到5页
    for page in range(1,20):
        page_queue.put(page)
    #创建队列内容
    data_queue = Queue()
    return page_queue,data_queue

#主函数
def main():
    #创建队列函数
    page_queue,data_queue = create_queue()
    #打开文件
    fp = open('fanjianzhi.txt','a',encoding='utf8')
    #创建锁
    lock = threading.Lock()
    #创建采集线程
    create_crawl_thread(page_queue,data_queue)
    #一开始解析队列为空 所以需要等待一会
    time.sleep(10)
    #创建解析线程 解析线程存档时会用到fp 将其作为参数传入
    create_parse_thread(data_queue,fp,lock)
    #启动所有采集线程
    for tcrawl in g_crawl_list:
        tcrawl.start()
    #启动所有解析线程
    for tparse in g_parse_list:
        tparse.start()
    #主线程等待两个子线程结束
    for tcrawl in g_crawl_list:
        tcrawl.join()
    for tparse in g_parse_list:
        tparse.join()
    #在这里关闭文件
    fp.close()
    print("主线程子线程全部结束")



if __name__ == '__main__':
    main()

 这线程玩起来确实比常规爬取写起来要困难,但是据说效率高,而且也是爬虫正规化的必由之路,没办法,也得学

作者:求知鱼

-------------------------------------------

个性签名:你有一个苹果,我有一个苹果,我们交换一下,一人还是只有一个苹果;你有一种思想,我有一种思想,我们交换一下,一个人就有两种思想。

如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

独学而无友,则孤陋而寡闻,开源、分享、白嫖!

原文地址:https://www.cnblogs.com/Qiuzhiyu/p/12184526.html