爬取笔趣阁小说

# !/user/bin/env python3
# -*- coding: utf-8 -*-
# Author:Euler
import requests
import re
import os  # 文件夹及文件的判别设置
import time  # 用于有道翻译JS逆向中生成随机数
import hashlib  # 用于反反爬有道,用来做js逆向
from lxml import etree  # xpath方法
import threading  # 准备引入多线程实现异步爬虫
from random import choice  # 用于免费代理IP的随机选取  # choice从列表中选取合适项结果用因素表示,choices将选取结果做成列表 详见line25


# 小说爬取函数
def novel(name_, m, n):
    # 加入代理IP
    """
    proxy = {
        # "http": "http://11.11.11.11.123"  # 乱写的,不一定是可用的代理IP
        "http": "http://183.247.199.111:30001"  # 乱写的,不一定是可用的代理IP
    }
    """
    global text
    with open('D:/学习/六星/爬虫班预习/5.IP代理/免费IP.txt', 'r') as f:
        p = f.read().strip().split('\n')  # 变量l不明确
    proxy = eval(choice(p))  # 拿到免费代理IP
    # print(proxy)

    # 加入请求头
    headers_ = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/96.0.4664.45 Safari/537.36 '
    }
    # name = input('输入书名:')  # 输入书名
    # 可以索引的url,笔趣阁网站
    url_raw = 'https://www.bige7.com/s?q={}'.format(name_)  # 书名相关网址
    # 请求网页
    response = requests.get(url_raw, headers=headers_, proxies=proxy)  # 请求网页
    # html化
    html = etree.HTML(response.content.decode())  # 将之HTML化
    # 通过xpath获取章节名
    text_name = html.xpath('//h4[@class="bookname"]/a/text()')  # 用xpath方法获取章节名
    # 循环获取对应的书的链接
    href = ''
    # 多个书中获取链接
    for k in range(len(text_name)):
        if name_ in text_name:
            href = html.xpath('//h4[@class="bookname"]/a/@href')[text_name.index(name_)]
        else:
            if name_ in text_name[k]:
                href = html.xpath('//h4[@class="bookname"]/a/@href')[k]
    if href == '':
        return print('未搜索到该书!')
    # n = int(input('输入爬取章数:'))  # 获取爬取页数
    # 循环通过动态url获取从某起始章到某终结章
    for i in range(m, n + 1):
        # 循环获取动态url
        url = f'https://www.bige7.com{href}{i}.html'
        # 请求网页,获取网页源码
        res = requests.get(url, headers=headers_, proxies=proxy)
        # 解析网页
        str_data = res.content.decode()
        # 获取书名
        file_name = '《' + re.findall('<title>(.*?)</title>', str_data)[0][
                          :re.findall('<title>(.*?)</title>', str_data)[0].find('_')].replace(':', ',') + '》'
        # 如果不存在该书名文件夹则新建,否则略过,创建文件夹
        if not os.path.exists(file_name) and '最新' not in file_name and '页面不存' not in file_name:
            os.makedirs(file_name)

        try:
            # 获取每一章节名
            title = re.findall('<span class="title">(.*?)</span>', str_data)[0]
            # 排除符号干扰,排除符号干扰,title已经在第一次符号过滤时发生改变
            for j in title:
                if j == ':' or j == '_' or j == '?':
                    title = title[:title.find(j)]
                    break
                # 获取该章节内容
                # 获取内容
                text = re.findall('<div id="chaptercontent" class="Readarea ReadAjax_content">(.*)', str_data)[
                    0].replace(
                    '<br />', '\n')
        except IndexError:
            # latest_chapter
            # 获取最新章节名
            url_ = f'https://www.bige7.com{href}'
            # print(url_)
            # 获取网页源码
            res_ = requests.get(url_, headers=headers_, proxies=proxy).content.decode()
            html_ = etree.HTML(res_)
            latest_chapter = html_.xpath('//span[@class="last"]/a/text()')[0]
            print(f'最新章节为:{latest_chapter}')
            break
        # 存入对应文件夹
        with open(f'{file_name}/{title}.txt', 'w+', encoding='utf-8') as f:
            f.write(text)
            print(title + '------------下载成功!')


def idm(name_, d_):
    # 在下载的章节数大于等于15时启动多线程
    if len(name_) == 1 and (int(d_[name_[0]][1]) - int(d_[name_[0]][0]) + 1) >= 20:
        length = int(d_[name_[0]][1]) - int(d_[name_[0]][0]) + 1
        temp = int(d_[name_[0]][1])
        # l = int(input('输入次数:'))
        # 至少分20个多线程,每个线程启用一个代理IP,可以根据输入总章节数,每一章分一个线程
        r = 20
        for j in range(r):
            m = int(d_[name_[0]][0]) + (length / r) * j + j
            n = m + length / r
            if n > temp:
                n = temp
            s = threading.Thread(target=novel, args=(name_[0], int(m), int(n)))
            s.start()
    else:
        for j in name_:
            s = threading.Thread(target=novel, args=(j, int(d_[j][0]), int(d_[j][1])))
            s.start()


# 主程序入口
if __name__ == '__main__':
    start_time = time.time()
    try:
        # 获取书名
        name = input('输入需要爬取的书名(用空格隔开):').split(' ')
        # 定义空字典用于得到对应信息,并将之编成键值对
        d = {}
        # 添加字典内容
        for o in range(len(name)):
            d[name[o]] = input('输入%s爬取的起始章和终结章(用空格隔开):' % name[o]).strip().split(' ')
        # 用主循环多线程同时爬取多本小说内容
        idm(name, d)

    except Exception as e:
        pass
    finally:
        print('所用时间:{}'.format(time.time() - start_time))
        pass
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一笑_奈何

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值