鱼C论坛

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

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

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

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

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

x
今天抽了两三个钟头学了学多线程相关的东西
比葫芦画瓢,算是画出来东西了
内容:下载《赘婿》全文并保存为txt
提示:初次尝试,全文保存为txt是会把记事本卡爆的哦
仅作参考

  1. """
  2. 多线程爬虫首次尝试:
  3.     爬取赘婿小说全部章节,解析并保存为txt
  4.     目标url:http://www.xbiquge.la/0/885/
  5. @author: 昨非
  6. """

  7. from threading import Thread
  8. from queue import Queue
  9. from fake_useragent import UserAgent
  10. import requests
  11. from lxml import etree

  12. headers = {
  13.     "User-Agent": UserAgent().random
  14. }
  15. # 爬虫类
  16. class GetInfo(Thread):
  17.     def __init__(self,url_queue,html_queue):
  18.         Thread.__init__(self)
  19.         self.url_queue = url_queue
  20.         self.html_queue = html_queue

  21.     def run(self):
  22.         while self.url_queue.empty() == False:
  23.             url = self.url_queue.get()
  24.             response = requests.get(url, headers=headers)
  25.             if response.status_code == 200:
  26.                 response.encoding = 'utf-8'  # 这步很关键
  27.                 self.html_queue.put(response.text)

  28. # 解析类
  29. class ParseInfo(Thread):
  30.     def __init__(self, html_queue):
  31.         Thread.__init__(self)
  32.         self.html_queue = html_queue

  33.     def run(self):
  34.         while self.html_queue.empty() == False:
  35.             e = etree.HTML(self.html_queue.get())
  36.             chapter_names = e.xpath('//div[@class = "bookname"]/h1/text()')
  37.             chapter_contents = e.xpath('//div[@id = "content"]/text()')
  38.             for chapter_name in chapter_names:

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

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


  48. if __name__ == '__main__':
  49.     # 存储url的容器
  50.     url_queue = Queue()
  51.     # 存储内容的容器
  52.     html_queue = Queue()

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

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

  66.     for crawl in crawl_list:
  67.         crawl.join()

  68.     parse_list = []
  69.     for i in range(0, 100):
  70.         parse = ParseInfo(html_queue)
  71.         parse_list.append(parse)
  72.         parse.start()
  73.     for parse in parse_list:
  74.         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 | 显示全部楼层
优先队列,顺序问题已解决,更新代码如下:
  1. """
  2. 多线程爬虫首次尝试:
  3.     爬取赘婿小说全部章节,解析并保存为txt
  4.     目标url:http://www.xbiquge.la/0/885/
  5. @author: 昨非
  6. """

  7. from threading import Thread
  8. from queue import PriorityQueue
  9. from fake_useragent import UserAgent
  10. import requests
  11. from lxml import etree

  12. headers = {
  13.     "User-Agent": UserAgent().random
  14. }
  15. # 爬虫类
  16. class GetInfo(Thread):
  17.     def __init__(self,url_queue,html_queue):
  18.         Thread.__init__(self)
  19.         self.url_queue = url_queue
  20.         self.html_queue = html_queue

  21.     def run(self):
  22.         while self.url_queue.empty() == False:
  23.             item = self.url_queue.get()
  24.             url = item[1]
  25.             response = requests.get(url, headers=headers)
  26.             if response.status_code == 200:
  27.                 response.encoding = 'utf-8'  # 这步很关键
  28.                 self.html_queue.put((item[0],response.text))

  29. # 解析类
  30. class ParseInfo(Thread):
  31.     def __init__(self, html_queue):
  32.         Thread.__init__(self)
  33.         self.html_queue = html_queue

  34.     def run(self):
  35.         while self.html_queue.empty() == False:
  36.             item2 = self.html_queue.get()
  37.             e = etree.HTML(item2[1])
  38.             chapter_names = e.xpath('//div[@class = "bookname"]/h1/text()')
  39.             chapter_contents = e.xpath('//div[@id = "content"]/text()')
  40.             for chapter_name in chapter_names:

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

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


  50. if __name__ == '__main__':
  51.     # 存储url的容器
  52.     url_queue = PriorityQueue()
  53.     # 存储内容的容器
  54.     html_queue = PriorityQueue()

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




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

  70.     for crawl in crawl_list:
  71.         crawl.join()

  72.     parse_list = []
  73.     for i in range(0, 100):
  74.         parse = ParseInfo(html_queue)
  75.         parse_list.append(parse)
  76.         parse.start()
  77.     for parse in parse_list:
  78.         parse.join()
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 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

GMT+8, 2021-5-13 02:05

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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