对于广大书虫而言,没有小说看是最痛苦的,你身边有这样的人吗?

今天咱们分享一个小说下载器代码,打包成exe后,发给你的小伙伴也能直接使用…

思路流程什么是爬虫?

按照一定的规则, 去采集互联网上面数据

爬虫可以做什么?

  • 采集数据: 定制化采集数据
  • 自动化脚本:自动点赞/评论/刷票/商品抢购脚本/自动发送弹幕

爬虫基本实现思路?

一、数据来源分析

  1. 明确需求:
    – 采集的网站是什么?
    https://www.biqudu.net/1_1631/3047505.html
    – 采集的数据是什么?
    标题/内容
  2. 分析 标题/内容 是从哪里来的
    通过浏览器自带工具: 开发者工具抓包分析
    – 打开开发者工具: F12 / 鼠标右键点击检查选择network
    – 刷新网页
    – 搜索数据, 找到数据包
    https://www.biqudu.net/1_1631/3047505.html

二. 代码实现步骤

  1. 发送请求, 模拟浏览器对于url地址发送请求
    请求链接: https://www.biqudu.net/1_1631/3047505.html
  2. 获取数据, 获取服务器返回响应数据内容
    开发者工具: response
  3. 解析数据, 提取我们想要的数据内容
    标题/内容
  4. 保存数据, 把数据保存本地文件

代码实现

在开始之前,为了防止大家代码看不懂,我特地录制了一套详细教程,教程和代码,直接加这个裙 708525271 自取就好了

一、单张小说下载

发送请求, 模拟浏览器对于url地址发送请求
获取数据, 获取服务器返回响应数据内容

import requests# 请求链接url = 'https://www.biqudu.net/1_1631/3047505.html'# 模拟浏览器 headers 请求头headers = {    # user-agent 用户代理 表示浏览器基本身份信息    'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}# 发送请求response = requests.get(url=url, headers=headers)#  响应对象, 表示请求成功print(response)print(response.text)

解析数据,提取我们想要的数据内容。

import requests  # 数据请求import re  # 正则import parsel # 数据解析# 请求链接url = 'https://www.biqudu.net/1_1631/3047505.html'# 模拟浏览器 headers 请求头headers = {    # user-agent 用户代理 表示浏览器基本身份信息    'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}# 发送请求response = requests.get(url=url, headers=headers)#  响应对象, 表示请求成功print(response)# 获取下来response.text , 转成可解析对象selector = parsel.Selector(response.text)# 提取标题title = selector.xpath('//*[@class="bookname"]/h1/text()').get()# 提取内容content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())print(title)print(content)

保存数据

# 数据请求模块 import requests# 正则表达式模块import re# 数据解析模块import parsel # 请求链接url = 'https://www.biqudu.net/1_1631/3047505.html'# 模拟浏览器 headers 请求头headers = {    # user-agent 用户代理 表示浏览器基本身份信息    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}# 发送请求response = requests.get(url=url, headers=headers)#  响应对象, 表示请求成功print(response)# 获取下来response.text , 转成可解析对象selector = parsel.Selector(response.text)# 提取标题title = selector.xpath('//*[@class="bookname"]/h1/text()').get()# 提取内容content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())print(title)print(content)# title  '.txt' 文件格式  a 追加保存 encoding 编码格式 as 重命名with open(title + '.txt', mode='a', encoding='utf-8') as f:    # 写入内容    f.write(title)    f.write('\n')    f.write(content)    f.write('\n')

二、整本小说下载

# 数据请求模块import requests# 正则表达式模块import re# 数据解析模块import parsel# 文件操作模块import os # 请求链接: 小说目录页list_url = 'https://www.biqudu.net/1_1631/'# 模拟浏览器 headers 请求头headers = {    # user-agent 用户代理 表示浏览器基本身份信息    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}# 发送请求html_data = requests.get(url=list_url, headers=headers).text# 提取小说名字name = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0]# 自动创建一个文件夹file = f'{name}\\'if not os.path.exists(file): os.mkdir(file) # 提取章节urlurl_list = re.findall('
', html_data)# for循环遍历for url in url_list: index_url = 'https://www.biqudu.net' + url print(index_url) headers = { # user-agent 用户代理 表示浏览器基本身份信息 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36' } # 发送请求 response = requests.get(url=index_url, headers=headers) # 响应对象, 表示请求成功 print(response) # 获取下来response.text , 转成可解析对象 selector = parsel.Selector(response.text) # 提取标题 title = selector.xpath('//*[@class="bookname"]/h1/text()').get() # 提取内容 content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall()) print(title) # print(content) # title '.txt' 文件格式 a 追加保存 encoding 编码格式 as 重命名 with open(file + title + '.txt', mode='a', encoding='utf-8') as f: # 写入内容 f.write(title) f.write('\n') f.write(content) f.write('\n')

三、多线程采集

# 数据请求模块import requests# 正则表达式模块import re# 数据解析模块import parsel# 文件操作模块import os# 线程池import concurrent.futures  def get_response(html_url):    """    发送请求函数    :param html_url: 请求链接    :return: response响应对象    """    # 模拟浏览器 headers 请求头    headers = {        # user-agent 用户代理 表示浏览器基本身份信息        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'    }    response = requests.get(url=html_url, headers=headers)    return response  def get_list_url(html_url):    """    获取章节url/小说名    :param html_url: 小说目录页    :return:    """    # 调用发送请求函数    html_data = get_response(html_url).text    # 提取小说名字    name = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取章节url url_list = re.findall('
', html_data) return name, url_list def get_content(html_url): """ 获取小说内容/小说标题 :param html_url: 小说章节url :return: """ # 调用发送请求函数 html_data = get_response(html_url).text # 提取标题 title = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取内容 content = re.findall('
https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data, re.S)[0].replace('

', '\n') return title, content def save(name, title, content): """ 保存数据函数 :param name: 小说名 :param title: 章节名 :param content: 内容 :return: """ # 自动创建一个文件夹 file = f'{name}\\' if not os.path.exists(file): os.mkdir(file) with open(file + title + '.txt', mode='a', encoding='utf-8') as f: """ 第一章 标题 小说内容 第二章 标题 小说内容 """ # 写入内容 f.write(title) f.write('\n') f.write(content) f.write('\n') print(title, '已经保存') def main(home_url): # index_url = 'https://www.biqudu.net' + url title, content = get_content(html_url=home_url) save(name, title, content) if __name__ == '__main__': url = 'https://www.biqudu.net/1_1631/' name, url_list = get_list_url(html_url=url) exe = concurrent.futures.ThreadPoolExecutor(max_workers=7) for url in url_list: index_url = 'https://www.biqudu.net' + url exe.submit(main, index_url) exe.shutdown()

四、采集排行榜所有小说

# 数据请求模块import requests# 正则表达式模块import re# 数据解析模块import parsel# 文件操作模块import os   def get_response(html_url):    """    发送请求函数    :param html_url: 请求链接    :return: response响应对象    """    # 模拟浏览器 headers 请求头    headers = {        # user-agent 用户代理 表示浏览器基本身份信息        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'    }    response = requests.get(url=html_url, headers=headers)    return response  def get_list_url(html_url):    """    获取章节url/小说名    :param html_url: 小说目录页    :return:    """    # 调用发送请求函数    html_data = get_response(html_url).text    # 提取小说名字    name = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取章节url url_list = re.findall('
', html_data) return name, url_list def get_content(html_url): """ 获取小说内容/小说标题 :param html_url: 小说章节url :return: """ # 调用发送请求函数 html_data = get_response(html_url).text # 提取标题 title = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取内容 content = re.findall('
https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data, re.S)[0].replace('

', '\n') return title, content def save(name, title, content): """ 保存数据函数 :param name: 小说名 :param title: 章节名 :param content: 内容 :return: """ # 自动创建一个文件夹 file = f'{name}\\' if not os.path.exists(file): os.mkdir(file) with open(file + title + '.txt', mode='a', encoding='utf-8') as f: """ 第一章 标题 小说内容 第二章 标题 小说内容 """ # 写入内容 f.write(title) f.write('\n') f.write(content) f.write('\n') print(title, '已经保存') def get_novel_id(html_url): """ 获取小说ID :param html_url: 某分类的链接 :return: """ # 调用发送请求函数 novel_data = get_response(html_url=html_url).text selector = parsel.Selector(novel_data) href = selector.css('.l .s2 a::attr(href)').getall() href = [i.replace('/', '') for i in href] return href def main(home_url): href = get_novel_id(html_url=home_url) for novel_id in href: novel_url = f'https://www.biqudu.net/{novel_id}/' name, url_list = get_list_url(html_url=novel_url) print(name, url_list) for url in url_list: index_url = 'https://www.biqudu.net' + url title, content = get_content(html_url=index_url) save(name, title, content) break if __name__ == '__main__': html_url = 'https://www.biqudu.net/biquge_1/' main(html_url)

五、搜索小说功能

模块

# 导入数据请求模块import requests# 导入正则表达式模块import re# 导入数据解析模块import parsel# 导入文件操作模块import os# 导入漂亮的表格import prettytable as pt

发送请求函数

def get_response(html_url):    # 模拟浏览器 headers 请求头    headers = {        # user-agent 用户代理 表示浏览器基本身份信息        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'    }    response = requests.get(url=html_url, headers=headers)    return response

获取章节url/小说名

def get_list_url(html_url):    # 调用发送请求函数    html_data = get_response(html_url).text    # 提取小说名字    name = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取章节url url_list = re.findall('
', html_data) return name, url_list

获取小说内容/小说标题

def get_content(html_url):    # 调用发送请求函数    html_data = get_response(html_url).text    # 提取标题    title = re.findall('

https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data)[0] # 提取内容 content = re.findall('
https://www.cnblogs.com/hahaa/archive/2023/02/17/(.*?)

', html_data, re.S)[0].replace('

', '\n') return title, content

保存数据函数

def save(name, title, content):    # 自动创建一个文件夹    file = f'{name}\\'    if not os.path.exists(file):        os.mkdir(file)    with open(file + name + '.txt', mode='a', encoding='utf-8') as f:        # 写入内容        f.write(title)        f.write('\n')        f.write(content)        f.write('\n')    print(title, '已经保存')

获取小说ID

def get_novel_id(html_url):    # 调用发送请求函数    novel_data = get_response(html_url=html_url).text    selector = parsel.Selector(novel_data)    href = selector.css('.l .s2 a::attr(href)').getall()    href = [i.replace('/', '') for i in href]    return href

搜索功能

def search(word):    search_url = f'https://www.biqudu.net/searchbook.php?keyword={word}'    # 发送请求    search_data = get_response(html_url=search_url).text    # 解析数据, 提取小说名字/作者/小说ID    selector = parsel.Selector(search_data)    lis = selector.css('.novelslist2 li')    novel_info = []    tb = pt.PrettyTable()    tb.field_names = ['序号', '书名', '作者', '书ID']    num = 0    for li in lis[1:]:        # 小说名字        name = li.css('.s2 a::text').get()        novel_id = li.css('.s2 a::attr(href)').get().replace('/', '')        writer = li.css('.s4::text').get()        dit = {            'name': name,            'writer': writer,            'novel_id': novel_id,        }        tb.add_row([num, name, writer, novel_id])        num += 1        novel_info.append(dit)    print('你搜索的结果如下:')    print(tb)    novel_num = input('请输入你想要下载的小说序号: ')    novel_id = novel_info[int(novel_num)]['novel_id']    return novel_id

主函数

def main(word):    novel_id = search(word)    novel_url = f'https://www.biqudu.net/{novel_id}/'    name, url_list = get_list_url(html_url=novel_url)    print(name, url_list)    for url in url_list:        index_url = 'https://www.biqudu.net' + url        title, content = get_content(html_url=index_url)        save(name, title, content)        if __name__ == '__main__':    word = input('请输入你搜索小说名: ')    main(word)

效果展示

六、GUI界面

import tkinter as tkfrom tkinter import ttk   def show():    name = name_va.get()    print('输入的名字是:', name) def download():    name = num_va.get()    print('输入的序号:', name)  # 创建界面root = tk.Tk()# 设置标题root.title('完整代码添加VX:pytho8987')# 设置界面大小root.geometry('500x500+200+200')# 设置可变变量name_va = tk.StringVar()# 设置标签search_frame = tk.Frame(root)search_frame.pack(pady=10)# 设置文本tk.Label(search_frame, text='书名 作者', font=('微软雅黑', 15)).pack(side=tk.LEFT, padx=10)# 设置输入框tk.Entry(search_frame, relief='flat', textvariable=name_va).pack(side=tk.LEFT) # 序号获取num_va = tk.StringVar()# 查询下载输入框download_frame = tk.Frame(root)download_frame.pack(pady=10)# 设置文本tk.Label(download_frame, text='小说 序号', font=('微软雅黑', 15)).pack(side=tk.LEFT, padx=10)# 设置输入框tk.Entry(download_frame, relief='flat', textvariable=num_va).pack(side=tk.LEFT) # 按钮设置button_frame = tk.Frame(root)button_frame.pack(pady=10) # 设置查询按钮tk.Button(button_frame, text='查询', font=('微软雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=show).pack(side=tk.LEFT, padx=10)# 设置下载按钮tk.Button(button_frame, text='下载', font=('微软雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=download).pack(side=tk.LEFT, padx=10) # 提前设置标签名字和中文显示内容columns = ('num', 'writer', 'name', 'novel_id')columns_value = ('序号', '作者', '书名', '书ID')tree_view = ttk.Treeview(root, height=18, show='headings', columns=columns)# 设置列名# 设置列名tree_view.column('num', width=40, anchor='center')tree_view.column('writer', width=40, anchor='center')tree_view.column('name', width=40, anchor='center')tree_view.column('novel_id', width=40, anchor='center')# 给列名设置显示的名字tree_view.heading('num', text='序号')tree_view.heading('writer', text='作者')tree_view.heading('name', text='书名')tree_view.heading('novel_id', text='书ID')tree_view.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)# 展示界面root.mainloop()

效果展示

最后

全部实现以后,我们可以使用 Pyinstaller 模块将代码打包为exe可执行软件,这样的话,就能分享给不会的小伙伴去使用了。

好了,今天的分享就到这里结束了,欢迎大家品鉴!下次见!