吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2019|回复: 21
收起左侧

[已解决] python3.7爬虫多线程请教!!!

[复制链接]
liuyouyong 发表于 2020-4-4 22:01
本帖最后由 liuyouyong 于 2020-4-4 23:55 编辑

我的代码可以直接复制到py里运行,爬个一千章需要快一小时。望大神改用多线程!!本人可以用多线程但是章节会乱就不好意思放出来了大神记得加注释
import requests,re,time,random    #导入requests包
from bs4 import BeautifulSoup  #大家懂得
##get  url的源码
def gethtml(url):
##头~~~~~~
    header = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Connection': 'keep-alive',
        'Accept-Encoding': 'br, gzip, deflate',
        'Accept-Language':'zh-cn',
        'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10'
    }
    #设置一个超时时间 取随机数 是为了防止网站被认定为爬虫
    timeout = random.choice(range(800,1800))
    html=requests.get(url=url,headers=header,timeout=timeout)
    html.encoding = html.apparent_encoding
    return html.text

##获得网页源码后清洗里面的网页字符
def fre(html):
    res ={r'<br/>',
          r'[<div id="BookText">',
          r'一秒记住【风雨小说网 www.44pq.cc】,精彩小说无弹窗免费阅读!',
          r'</div>]',
          r'<h1>',
          r'</h1>',
        }
    for i in res:
        html = str(html).replace(i,'')
    return html

##用BeautifulSoup清洗
def htmlse(url,sel,namesel=''):
    html = gethtml(url)
    soup=BeautifulSoup(html,'lxml')
    data = soup.select(sel)
    if namesel == '':
        return data
    name = soup.select(namesel)
    return name,data

##用re正则清洗
def htmlre(html,res):
    htmllist=[]
    for i in html:
        a = re.findall(res,str(i))
        if a : htmllist.append(a[0])
    return htmllist

if __name__ == "__main__":
    start = time.time()  #开始时间
    url = 'https://www.44pq.cc/kan/151682/'
    sel = r'body > div.container > div.main > div > dl > dd'
    namesel = r'#BookCon > h1'
    selz = r'#BookText'
    res = r'href="(.*.html)'
    htmllist = htmlre(htmlse(url,sel),res)
    for i in range(0,10): #len(htmllist)
        text = htmlse(url+htmllist,selz,namesel)
        print (fre(text[0]))
        with open('万古第一神.txt', 'a', encoding='utf-8') as f:
            f.write(fre(text[0]))
            f.write(fre(text[1]))
            f.write('\n'*5)
        #time.sleep(0.2)
    print('%.1f' % (float(time.time()-start))) #结束时间




   

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

muyan1995 发表于 2020-4-4 23:24
建议楼主把整篇文章拿下来后统一储存,下面是我的代码,清洗和异常处理部分你可以自己优化下,开了30线程,一分钟左右就保存好了。我这里用的是python 3.6.8,在3.7下应该也可以用,具体没测试。
[Python] 纯文本查看 复制代码
import requests
import threading
import queue
import logging
from lxml import etree

producer_threading_num = 1  # 生产线程数
consume_threading_num = 30  # 消费线程数


def get_html(url):
    """
    由于都是get请求因此在这里统一封装
    :param url:
    :return:
    """
    headers = {
        "Host": "www.44pq.cc",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/80.0.3987.132 Safari/537.36"}
    response = requests.get(
        url=url,
        headers=headers,
        timeout=30
    )
    if response.status_code == 200:
        response.encoding = 'gb18030'
        return response.text
    return None


class ProducerPart(threading.Thread):
    """
    生产者
    """
    def __init__(self, q):
        super(ProducerPart, self).__init__()
        self.q = q

    def run(self):
        url = 'https://www.44pq.cc/kan/151682/'  # 列表页url
        response_text = get_html(url)
        if response_text:
            _html = etree.HTML(response_text)
            list_part = _html.xpath('/html/body/div[3]/div[3]/div/dl/dd/a')
            for _chapter in list_part:
                chapter_name = _chapter.xpath(
                    'text()')[0] if _chapter.xpath('text()') else ''  # 章节名称
                chapter_url = 'https://www.44pq.cc/kan/151682/' + \
                    _chapter.xpath('@href')[0] if _chapter.xpath('@href') else ''  # 章节链接
                if all([chapter_name, chapter_url]):
                    self.q.put(chapter_url + '|' + chapter_name)
                else:
                    print('{} 内容缺失'.format(chapter_name))
        else:
            print('本次请求 {} 失败'.format(url))


class ConsumePart(threading.Thread):
    """
    消费者
    """
    def __init__(self, q, num):
        super(ConsumePart, self).__init__()
        self.q = q
        self.q_num = num

    def run(self):
        for i in range(10):
            while True:
                try:
                    content = self.q.get(block=True, timeout=60)
                    chapter_url = content.split('|')[0]  # 章节名称
                    chapter_name = content.split('|')[1]  # 章节链接
                    response_text = get_html(chapter_url)
                    if response_text:
                        _html = etree.HTML(response_text)
                        text_part = _html.xpath('//*[@id="BookCon"]//text()')
                        _text = ''.join(text_part).strip()  # 详情页
                        with open('{}.text'.format(chapter_name), 'w', encoding='utf-8') as f:
                            f.write(_text)
                    else:
                        print('本次请求 {} 失败'.format(chapter_url))
                except queue.Empty:
                    logging.warning('queue is empty')
                    break
        logging.warning('threading {} is end'.format(self.q_num))


def main():
    try:
        q = queue.Queue(1000)
        for i in range(producer_threading_num):
            t = ProducerPart(q)
            t.setDaemon(True)
            t.start()
        for j in range(consume_threading_num):
            s = ConsumePart(q, j)
            s.setDaemon(False)
            s.start()
    except Exception as e:
        logging.warning('main Exception as {}'.format(e))


if __name__ == "__main__":
    main()

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
liuyouyong + 1 + 1 谢谢@Thanks!

查看全部评分

寒尘丶Coldust 发表于 2020-4-4 22:27
Python的多线程因为有GIL的存在 效率反而没那么高...
小程序的话可以改成多进程方式 可以并行
非法菜鸟 发表于 2020-4-4 22:34
给你个思路试试  
第一步 多线程进行网页爬取  并按章节给爬取到的结果编号
第二步 将带有编号的结果内容放到一个 缓存(例如元组)中
第三步 启动一个线程 死循环 读取缓存内容  把里面的内容顺序写入到文件中 直到结束
JOB123 发表于 2020-4-4 22:35
    #设置一个超时时间 取随机数 是为了防止网站被认定为爬虫
    timeout = random.choice(range(800,1800))
    html=requests.get(url=url,headers=header,timeout=timeout)
楼主你恐怕是理解错了...
wifi啦啦啦 发表于 2020-4-4 22:41
就我亲身经历写多线程爬虫爬小说,把每一章缓存到一个文件夹(我是小白,只想到这个),全部缓存之后,再用os库的索引把文件夹每一章按序列整合成一个txt就好了
wifi啦啦啦 发表于 2020-4-4 22:43
多线程要设置线程锁,速度也是快得一批,十分钟不到一千多章就完了
我创建的多线程是这样:
            ts = []
            for j in range(24):
                t = threading.Thread(target=a.get_chapter, args=(wifi,))
                ts.append(t)
            for j in range(24):
                t = ts[j]
                t.start()
            for j in range(24):
                t = ts[j]
                t.join()
wifi啦啦啦 发表于 2020-4-4 22:45
进程锁部分就要看你自己的程序了,没设置好的话,就会下载你设置的线程数遍小说。。。
平繁 发表于 2020-4-4 22:58
JOB123 发表于 2020-4-4 22:35
#设置一个超时时间 取随机数 是为了防止网站被认定为爬虫
    timeout = random.choice(range(800,180 ...

lz的这个超时我也看的有点懵啊
 楼主| liuyouyong 发表于 2020-4-4 23:02
非法菜鸟 发表于 2020-4-4 22:34
给你个思路试试  
第一步 多线程进行网页爬取  并按章节给爬取到的结果编号
第二步 将带有编号的结果内 ...

谢谢,给的思路很好,
 楼主| liuyouyong 发表于 2020-4-4 23:05
wifi啦啦啦 发表于 2020-4-4 22:41
就我亲身经历写多线程爬虫爬小说,把每一章缓存到一个文件夹(我是小白,只想到这个),全部缓存之后,再用 ...

以前我以前也是这样的。因为现在想学多线程
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-30 06:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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