鱼C论坛

 找回密码
 立即注册
查看: 2676|回复: 11

[技术交流] 【爬虫】初次使用多线程

[复制链接]
发表于 2021-4-17 23:38:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
今天抽了两三个钟头学了学多线程相关的东西
比葫芦画瓢,算是画出来东西了
内容:下载《赘婿》全文并保存为txt
提示:初次尝试,全文保存为txt是会把记事本卡爆的哦
仅作参考
"""
多线程爬虫首次尝试:
    爬取赘婿小说全部章节,解析并保存为txt
    目标url:http://www.xbiquge.la/0/885/
@author: 昨非
"""

from threading import Thread
from queue import Queue
from fake_useragent import UserAgent
import requests
from lxml import etree

headers = {
    "User-Agent": UserAgent().random
}
# 爬虫类
class GetInfo(Thread):
    def __init__(self,url_queue,html_queue):
        Thread.__init__(self)
        self.url_queue = url_queue
        self.html_queue = html_queue

    def run(self):
        while self.url_queue.empty() == False:
            url = self.url_queue.get()
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                response.encoding = 'utf-8'  # 这步很关键
                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())
            chapter_names = e.xpath('//div[@class = "bookname"]/h1/text()')
            chapter_contents = e.xpath('//div[@id = "content"]/text()')
            for chapter_name in chapter_names:

                txt = ''
                for i in chapter_contents:  # 先拼接
                    if i != '\n':
                        i = repr(i).replace(r'\xa0', '').replace("'", '')
                        txt += i
                txt = repr(txt).replace("\\n", '\n').replace('\\', '')
                txt = repr(txt).replace('rr', '\n')# 最终处理

                with open('赘婿.txt', 'a', encoding='utf-8') as f:
                    f.write(chapter_name + '\n'+txt)


if __name__ == '__main__':
    # 存储url的容器
    url_queue = Queue()
    # 存储内容的容器
    html_queue = Queue()

    first_url = 'http://www.xbiquge.la/0/885/'
    response = requests.get(first_url, headers=headers)
    e = etree.HTML(response.content.decode('utf-8'))  # 返回字符串
    urls = e.xpath('//div[@class="box_con"]/div[@id="list"]/dl/dd/a/@href')
    for url in urls:
        chapter_url = 'http://www.xbiquge.la' + url
        url_queue.put(chapter_url)

    # 创建一个爬虫
    crawl_list = []
    for i in range(0, 100):
        crawl1 = GetInfo(url_queue, html_queue)
        crawl_list.append(crawl1)
        crawl1.start()

    for crawl in crawl_list:
        crawl.join()

    parse_list = []
    for i in range(0, 100):
        parse = ParseInfo(html_queue)
        parse_list.append(parse)
        parse.start()
    for parse in parse_list:
        parse.join()

那么问题来了,这队列我也是第一次用,章节不按顺序该咋整呢
(我的“葫芦”就是这么教的,瓢只能做到这程度,求指点,大佬勿喷
QQ图片20210417232936.png

评分

参与人数 2荣誉 +10 鱼币 +10 贡献 +6 收起 理由
糖甜弯了嘴 + 5 + 5 + 3 666666~学习了
Daniel_Zhang + 5 + 5 + 3 厉害了

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-4-21 17:38:36 | 显示全部楼层
优先队列,顺序问题已解决,更新代码如下:
"""
多线程爬虫首次尝试:
    爬取赘婿小说全部章节,解析并保存为txt
    目标url:http://www.xbiquge.la/0/885/
@author: 昨非
"""

from threading import Thread
from queue import PriorityQueue
from fake_useragent import UserAgent
import requests
from lxml import etree

headers = {
    "User-Agent": UserAgent().random
}
# 爬虫类
class GetInfo(Thread):
    def __init__(self,url_queue,html_queue):
        Thread.__init__(self)
        self.url_queue = url_queue
        self.html_queue = html_queue

    def run(self):
        while self.url_queue.empty() == False:
            item = self.url_queue.get()
            url = item[1]
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                response.encoding = 'utf-8'  # 这步很关键
                self.html_queue.put((item[0],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:
            item2 = self.html_queue.get()
            e = etree.HTML(item2[1])
            chapter_names = e.xpath('//div[@class = "bookname"]/h1/text()')
            chapter_contents = e.xpath('//div[@id = "content"]/text()')
            for chapter_name in chapter_names:

                txt = ''
                for i in chapter_contents:  # 先拼接
                    if i != '\n':
                        i = repr(i).replace(r'\xa0', '').replace("'", '')
                        txt += i
                txt = repr(txt).replace("\\n", '\n').replace('\\', '')
                txt = repr(txt).replace('rr', '\n')# 最终处理

                with open('赘婿.txt', 'a', encoding='utf-8') as f:
                    f.write(chapter_name + '\n'+txt + '\n')


if __name__ == '__main__':
    # 存储url的容器
    url_queue = PriorityQueue()
    # 存储内容的容器
    html_queue = PriorityQueue()

    first_url = 'http://www.xbiquge.la/0/885/'
    response = requests.get(first_url, headers=headers)
    e = etree.HTML(response.content.decode('utf-8'))  # 返回字符串
    urls = e.xpath('//div[@class="box_con"]/div[@id="list"]/dl/dd/a/@href')
    i = 0
    for url in urls:
        chapter_url = 'http://www.xbiquge.la' + url
        url_queue.put((i,chapter_url))
        i += 1




    # 创建一个爬虫
    crawl_list = []
    for i in range(0, 100):
        crawl1 = GetInfo(url_queue, html_queue)
        crawl_list.append(crawl1)
        crawl1.start()

    for crawl in crawl_list:
        crawl.join()

    parse_list = []
    for i in range(0, 100):
        parse = ParseInfo(html_queue)
        parse_list.append(parse)
        parse.start()
    for parse in parse_list:
        parse.join()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2021-4-17 23:51:33 | 显示全部楼层
体验还行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-4-18 07:56:05 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-4-18 09:12:36 From FishC Mobile | 显示全部楼层
无序的小说还能看吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-4-18 09:32:21 From FishC Mobile | 显示全部楼层
wp231957 发表于 2021-4-18 09:12
无序的小说还能看吗?

不能啊,我就试试
粗略搜了下,好像多线程乱序是挺经典的问题了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-4-18 14:02:35 | 显示全部楼层
找到突破口了:
优先队列加个序号来处理
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-4-20 00:17:22 | 显示全部楼层
本帖最后由 Daniel_Zhang 于 2021-4-20 00:19 编辑

我有一个想法,比如说你有 1000 个章节,那就分成 50 份,每一份做 20 个线程,然后 for 循环 50 次

每次 start 20 个线程

每个章节作为一个单独的 txt 文件

给一个线程锁,在完成 20 个线程之前不能继续接下来的操作

如果你想要多个 txt 合并的话,下载完成以后,单独搞一个 function 去合并,按照 txt 文件的名称什么的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-4-20 00:23:57 From FishC Mobile | 显示全部楼层
Daniel_Zhang 发表于 2021-4-20 00:17
我有一个想法,比如说你有 1000 个章节,那就分成 50 份,每一份做 20 个线程,然后 for 循环 50 次

每次 st ...

emmmm大晚上的不想思考,回头再说
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-4-21 19:53:15 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-4-24 21:05:58 | 显示全部楼层
用 concurrent.future 下的 map函数或者用协程
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-4-24 21:10:17 | 显示全部楼层
°蓝鲤歌蓝 发表于 2021-4-24 21:05
用 concurrent.future 下的 map函数或者用协程

听不懂,我先百度下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-16 00:01

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表