ToB企服应用市场:ToB评测及商务社交产业平台

标题: 用Python做一个小说下载器,从获取数据到编写GUI界面 [打印本页]

作者: 玛卡巴卡的卡巴卡玛    时间: 2023-2-17 22:37
标题: 用Python做一个小说下载器,从获取数据到编写GUI界面
对于广大书虫而言,没有小说看是最痛苦的,你身边有这样的人吗?
今天咱们分享一个小说下载器代码,打包成exe后,发给你的小伙伴也能直接使用…

思路流程

什么是爬虫?

按照一定的规则, 去采集互联网上面数据
爬虫可以做什么?

爬虫基本实现思路?

一、数据来源分析
二. 代码实现步骤
代码实现
  1. 在开始之前,为了防止大家代码看不懂,我特地录制了一套详细教程,教程和代码,直接加这个裙 708525271 自取就好了
复制代码
 


 
一、单张小说下载

发送请求, 模拟浏览器对于url地址发送请求
获取数据, 获取服务器返回响应数据内容
  1. import requests
  2. # 请求链接
  3. url = 'https://www.biqudu.net/1_1631/3047505.html'
  4. # 模拟浏览器 headers 请求头
  5. headers = {
  6.     # user-agent 用户代理 表示浏览器基本身份信息
  7.     'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  8. }
  9. # 发送请求
  10. response = requests.get(url=url, headers=headers)
  11. # <Response [200]> 响应对象, 表示请求成功
  12. print(response)
  13. print(response.text)
复制代码
 
解析数据,提取我们想要的数据内容。
  1. import requests  # 数据请求
  2. import re  # 正则
  3. import parsel # 数据解析
  4. # 请求链接
  5. url = 'https://www.biqudu.net/1_1631/3047505.html'
  6. # 模拟浏览器 headers 请求头
  7. headers = {
  8.     # user-agent 用户代理 表示浏览器基本身份信息
  9.     'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  10. }
  11. # 发送请求
  12. response = requests.get(url=url, headers=headers)
  13. # <Response [200]> 响应对象, 表示请求成功
  14. print(response)
  15. # 获取下来response.text <html字符串数据>, 转成可解析对象
  16. selector = parsel.Selector(response.text)
  17. # 提取标题
  18. title = selector.xpath('//*[@]/h1/text()').get()
  19. # 提取内容
  20. content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())
  21. print(title)
  22. print(content)
复制代码
 
保存数据
  1. # 数据请求模块
  2. import requests
  3. # 正则表达式模块
  4. import re
  5. # 数据解析模块
  6. import parsel
  7. # 请求链接
  8. url = 'https://www.biqudu.net/1_1631/3047505.html'
  9. # 模拟浏览器 headers 请求头
  10. headers = {
  11.     # user-agent 用户代理 表示浏览器基本身份信息
  12.     'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  13. }
  14. # 发送请求
  15. response = requests.get(url=url, headers=headers)
  16. # <Response [200]> 响应对象, 表示请求成功
  17. print(response)
  18. # 获取下来response.text <html字符串数据>, 转成可解析对象
  19. selector = parsel.Selector(response.text)
  20. # 提取标题
  21. title = selector.xpath('//*[@]/h1/text()').get()
  22. # 提取内容
  23. content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())
  24. print(title)
  25. print(content)
  26. # title <文件名> '.txt' 文件格式  a 追加保存 encoding 编码格式 as 重命名
  27. with open(title + '.txt', mode='a', encoding='utf-8') as f:
  28.     # 写入内容
  29.     f.write(title)
  30.     f.write('\n')
  31.     f.write(content)
  32.     f.write('\n')
复制代码
 
二、整本小说下载
  1. # 数据请求模块
  2. import requests
  3. # 正则表达式模块
  4. import re
  5. # 数据解析模块
  6. import parsel
  7. # 文件操作模块
  8. import os
  9. # 请求链接: 小说目录页
  10. list_url = 'https://www.biqudu.net/1_1631/'
  11. # 模拟浏览器 headers 请求头
  12. headers = {
  13.     # user-agent 用户代理 表示浏览器基本身份信息
  14.     'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  15. }
  16. # 发送请求
  17. html_data = requests.get(url=list_url, headers=headers).text
  18. # 提取小说名字
  19. name = re.findall('<h1>(.*?)</h1>', html_data)[0]
  20. # 自动创建一个文件夹
  21. file = f'{name}\\'
  22. if not os.path.exists(file):
  23.     os.mkdir(file)
  24. # 提取章节url
  25. url_list = re.findall('<dd> <a  target="_blank" href="https://www.cnblogs.com/(.*?)">', html_data)
  26. # for循环遍历
  27. for url in url_list:
  28.     index_url = 'https://www.biqudu.net' + url
  29.     print(index_url)
  30.     headers = {
  31.         # user-agent 用户代理 表示浏览器基本身份信息
  32.         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  33.     }
  34.     # 发送请求
  35.     response = requests.get(url=index_url, headers=headers)
  36.     # <Response [200]> 响应对象, 表示请求成功
  37.     print(response)
  38.     # 获取下来response.text <html字符串数据>, 转成可解析对象
  39.     selector = parsel.Selector(response.text)
  40.     # 提取标题
  41.     title = selector.xpath('//*[@]/h1/text()').get()
  42.     # 提取内容
  43.     content = '\n'.join(selector.xpath('//*[@id="content"]/text()').getall())
  44.     print(title)
  45.     # print(content)
  46.     # title <文件名> '.txt' 文件格式  a 追加保存 encoding 编码格式 as 重命名
  47.     with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
  48.         # 写入内容
  49.         f.write(title)
  50.         f.write('\n')
  51.         f.write(content)
  52.         f.write('\n')
复制代码
 
三、多线程采集
  1. # 数据请求模块
  2. import requests
  3. # 正则表达式模块
  4. import re
  5. # 数据解析模块
  6. import parsel
  7. # 文件操作模块
  8. import os
  9. # 线程池
  10. import concurrent.futures
  11. def get_response(html_url):
  12.     """
  13.     发送请求函数
  14.     :param html_url: 请求链接
  15.     :return: response响应对象
  16.     """
  17.     # 模拟浏览器 headers 请求头
  18.     headers = {
  19.         # user-agent 用户代理 表示浏览器基本身份信息
  20.         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  21.     }
  22.     response = requests.get(url=html_url, headers=headers)
  23.     return response
  24. def get_list_url(html_url):
  25.     """
  26.     获取章节url/小说名
  27.     :param html_url: 小说目录页
  28.     :return:
  29.     """
  30.     # 调用发送请求函数
  31.     html_data = get_response(html_url).text
  32.     # 提取小说名字
  33.     name = re.findall('<h1>(.*?)</h1>', html_data)[0]
  34.     # 提取章节url
  35.     url_list = re.findall('<dd> <a  target="_blank" href="https://www.cnblogs.com/(.*?)">', html_data)
  36.     return name, url_list
  37. def get_content(html_url):
  38.     """
  39.     获取小说内容/小说标题
  40.     :param html_url: 小说章节url
  41.     :return:
  42.     """
  43.     # 调用发送请求函数
  44.     html_data = get_response(html_url).text
  45.     # 提取标题
  46.     title = re.findall('<h1>(.*?)</h1>', html_data)[0]
  47.     # 提取内容
  48.     content = re.findall('(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
  49.     return title, content
  50. def save(name, title, content):
  51.     """
  52.     保存数据函数
  53.     :param name: 小说名
  54.     :param title: 章节名
  55.     :param content: 内容
  56.     :return:
  57.     """
  58.     # 自动创建一个文件夹
  59.     file = f'{name}\\'
  60.     if not os.path.exists(file):
  61.         os.mkdir(file)
  62.     with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
  63.         """
  64.         第一章 标题
  65.             小说内容
  66.         第二章 标题
  67.             小说内容
  68.         """
  69.         # 写入内容
  70.         f.write(title)
  71.         f.write('\n')
  72.         f.write(content)
  73.         f.write('\n')
  74.     print(title, '已经保存')
  75. def main(home_url):
  76.     # index_url = 'https://www.biqudu.net' + url
  77.     title, content = get_content(html_url=home_url)
  78.     save(name, title, content)
  79. if __name__ == '__main__':
  80.     url = 'https://www.biqudu.net/1_1631/'
  81.     name, url_list = get_list_url(html_url=url)
  82.     exe = concurrent.futures.ThreadPoolExecutor(max_workers=7)
  83.     for url in url_list:
  84.         index_url = 'https://www.biqudu.net' + url
  85.         exe.submit(main, index_url)
  86.     exe.shutdown()
复制代码
 
四、采集排行榜所有小说
  1. # 数据请求模块
  2. import requests
  3. # 正则表达式模块
  4. import re
  5. # 数据解析模块
  6. import parsel
  7. # 文件操作模块
  8. import os
  9. def get_response(html_url):
  10.     """
  11.     发送请求函数
  12.     :param html_url: 请求链接
  13.     :return: response响应对象
  14.     """
  15.     # 模拟浏览器 headers 请求头
  16.     headers = {
  17.         # user-agent 用户代理 表示浏览器基本身份信息
  18.         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  19.     }
  20.     response = requests.get(url=html_url, headers=headers)
  21.     return response
  22. def get_list_url(html_url):
  23.     """
  24.     获取章节url/小说名
  25.     :param html_url: 小说目录页
  26.     :return:
  27.     """
  28.     # 调用发送请求函数
  29.     html_data = get_response(html_url).text
  30.     # 提取小说名字
  31.     name = re.findall('<h1>(.*?)</h1>', html_data)[0]
  32.     # 提取章节url
  33.     url_list = re.findall('<dd> <a  target="_blank" href="https://www.cnblogs.com/(.*?)">', html_data)
  34.     return name, url_list
  35. def get_content(html_url):
  36.     """
  37.     获取小说内容/小说标题
  38.     :param html_url: 小说章节url
  39.     :return:
  40.     """
  41.     # 调用发送请求函数
  42.     html_data = get_response(html_url).text
  43.     # 提取标题
  44.     title = re.findall('<h1>(.*?)</h1>', html_data)[0]
  45.     # 提取内容
  46.     content = re.findall('(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
  47.     return title, content
  48. def save(name, title, content):
  49.     """
  50.     保存数据函数
  51.     :param name: 小说名
  52.     :param title: 章节名
  53.     :param content: 内容
  54.     :return:
  55.     """
  56.     # 自动创建一个文件夹
  57.     file = f'{name}\\'
  58.     if not os.path.exists(file):
  59.         os.mkdir(file)
  60.     with open(file + title + '.txt', mode='a', encoding='utf-8') as f:
  61.         """
  62.         第一章 标题
  63.             小说内容
  64.         第二章 标题
  65.             小说内容
  66.         """
  67.         # 写入内容
  68.         f.write(title)
  69.         f.write('\n')
  70.         f.write(content)
  71.         f.write('\n')
  72.     print(title, '已经保存')
  73. def get_novel_id(html_url):
  74.     """
  75.     获取小说ID
  76.     :param html_url: 某分类的链接
  77.     :return:
  78.     """
  79.     # 调用发送请求函数
  80.     novel_data = get_response(html_url=html_url).text
  81.     selector = parsel.Selector(novel_data)
  82.     href = selector.css('.l .s2 a::attr(href)').getall()
  83.     href = [i.replace('/', '') for i in href]
  84.     return href
  85. def main(home_url):
  86.     href = get_novel_id(html_url=home_url)
  87.     for novel_id in href:
  88.         novel_url = f'https://www.biqudu.net/{novel_id}/'
  89.         name, url_list = get_list_url(html_url=novel_url)
  90.         print(name, url_list)
  91.         for url in url_list:
  92.             index_url = 'https://www.biqudu.net' + url
  93.             title, content = get_content(html_url=index_url)
  94.             save(name, title, content)
  95.         break
  96. if __name__ == '__main__':
  97.     html_url = 'https://www.biqudu.net/biquge_1/'
  98.     main(html_url)
复制代码
 
五、搜索小说功能

模块
  1. # 导入数据请求模块
  2. import requests
  3. # 导入正则表达式模块
  4. import re
  5. # 导入数据解析模块
  6. import parsel
  7. # 导入文件操作模块
  8. import os
  9. # 导入漂亮的表格
  10. import prettytable as pt
复制代码
 
发送请求函数
  1. def get_response(html_url):
  2.     # 模拟浏览器 headers 请求头
  3.     headers = {
  4.         # user-agent 用户代理 表示浏览器基本身份信息
  5.         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
  6.     }
  7.     response = requests.get(url=html_url, headers=headers)
  8.     return response
复制代码
 
获取章节url/小说名
  1. def get_list_url(html_url):
  2.     # 调用发送请求函数
  3.     html_data = get_response(html_url).text
  4.     # 提取小说名字
  5.     name = re.findall('<h1>(.*?)</h1>', html_data)[0]
  6.     # 提取章节url
  7.     url_list = re.findall('<dd> <a  target="_blank" href="https://www.cnblogs.com/(.*?)">', html_data)
  8.     return name, url_list
复制代码
 
获取小说内容/小说标题
  1. def get_content(html_url):
  2.     # 调用发送请求函数
  3.     html_data = get_response(html_url).text
  4.     # 提取标题
  5.     title = re.findall('<h1>(.*?)</h1>', html_data)[0]
  6.     # 提取内容
  7.     content = re.findall('(.*?)<p>', html_data, re.S)[0].replace('<br/><br/>', '\n')
  8.     return title, content
复制代码
 
保存数据函数
  1. def save(name, title, content):
  2.     # 自动创建一个文件夹
  3.     file = f'{name}\\'
  4.     if not os.path.exists(file):
  5.         os.mkdir(file)
  6.     with open(file + name + '.txt', mode='a', encoding='utf-8') as f:
  7.         # 写入内容
  8.         f.write(title)
  9.         f.write('\n')
  10.         f.write(content)
  11.         f.write('\n')
  12.     print(title, '已经保存')
复制代码
 
获取小说ID
  1. def get_novel_id(html_url):
  2.     # 调用发送请求函数
  3.     novel_data = get_response(html_url=html_url).text
  4.     selector = parsel.Selector(novel_data)
  5.     href = selector.css('.l .s2 a::attr(href)').getall()
  6.     href = [i.replace('/', '') for i in href]
  7.     return href
复制代码
 
搜索功能
  1. def search(word):
  2.     search_url = f'https://www.biqudu.net/searchbook.php?keyword={word}'
  3.     # 发送请求
  4.     search_data = get_response(html_url=search_url).text
  5.     # 解析数据, 提取小说名字/作者/小说ID
  6.     selector = parsel.Selector(search_data)
  7.     lis = selector.css('.novelslist2 li')
  8.     novel_info = []
  9.     tb = pt.PrettyTable()
  10.     tb.field_names = ['序号', '书名', '作者', '书ID']
  11.     num = 0
  12.     for li in lis[1:]:
  13.         # 小说名字
  14.         name = li.css('.s2 a::text').get()
  15.         novel_id = li.css('.s2 a::attr(href)').get().replace('/', '')
  16.         writer = li.css('.s4::text').get()
  17.         dit = {
  18.             'name': name,
  19.             'writer': writer,
  20.             'novel_id': novel_id,
  21.         }
  22.         tb.add_row([num, name, writer, novel_id])
  23.         num += 1
  24.         novel_info.append(dit)
  25.     print('你搜索的结果如下:')
  26.     print(tb)
  27.     novel_num = input('请输入你想要下载的小说序号: ')
  28.     novel_id = novel_info[int(novel_num)]['novel_id']
  29.     return novel_id
复制代码
 
主函数
  1. def main(word):
  2.     novel_id = search(word)
  3.     novel_url = f'https://www.biqudu.net/{novel_id}/'
  4.     name, url_list = get_list_url(html_url=novel_url)
  5.     print(name, url_list)
  6.     for url in url_list:
  7.         index_url = 'https://www.biqudu.net' + url
  8.         title, content = get_content(html_url=index_url)
  9.         save(name, title, content)
  10.         
  11. if __name__ == '__main__':
  12.     word = input('请输入你搜索小说名: ')
  13.     main(word)
复制代码
 
效果展示

六、GUI界面
  1. import tkinter as tk
  2. from tkinter import ttk
  3. def show():
  4.     name = name_va.get()
  5.     print('输入的名字是:', name)
  6. def download():
  7.     name = num_va.get()
  8.     print('输入的序号:', name)
  9. # 创建界面
  10. root = tk.Tk()
  11. # 设置标题
  12. root.title('完整代码添加VX:pytho8987')
  13. # 设置界面大小
  14. root.geometry('500x500+200+200')
  15. # 设置可变变量
  16. name_va = tk.StringVar()
  17. # 设置标签
  18. search_frame = tk.Frame(root)
  19. search_frame.pack(pady=10)
  20. # 设置文本
  21. tk.Label(search_frame, text='书名 作者', font=('微软雅黑', 15)).pack(side=tk.LEFT, padx=10)
  22. # 设置输入框
  23. tk.Entry(search_frame, relief='flat', textvariable=name_va).pack(side=tk.LEFT)
  24. # 序号获取
  25. num_va = tk.StringVar()
  26. # 查询下载输入框
  27. download_frame = tk.Frame(root)
  28. download_frame.pack(pady=10)
  29. # 设置文本
  30. tk.Label(download_frame, text='小说 序号', font=('微软雅黑', 15)).pack(side=tk.LEFT, padx=10)
  31. # 设置输入框
  32. tk.Entry(download_frame, relief='flat', textvariable=num_va).pack(side=tk.LEFT)
  33. # 按钮设置
  34. button_frame = tk.Frame(root)
  35. button_frame.pack(pady=10)
  36. # 设置查询按钮
  37. tk.Button(button_frame, text='查询', font=('微软雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=show).pack(side=tk.LEFT, padx=10)
  38. # 设置下载按钮
  39. tk.Button(button_frame, text='下载', font=('微软雅黑', 10), relief='flat', bg='#88e2d6', width=10, command=download).pack(side=tk.LEFT, padx=10)
  40. # 提前设置标签名字和中文显示内容
  41. columns = ('num', 'writer', 'name', 'novel_id')
  42. columns_value = ('序号', '作者', '书名', '书ID')
  43. tree_view = ttk.Treeview(root, height=18, show='headings', columns=columns)
  44. # 设置列名
  45. # 设置列名
  46. tree_view.column('num', width=40, anchor='center')
  47. tree_view.column('writer', width=40, anchor='center')
  48. tree_view.column('name', width=40, anchor='center')
  49. tree_view.column('novel_id', width=40, anchor='center')
  50. # 给列名设置显示的名字
  51. tree_view.heading('num', text='序号')
  52. tree_view.heading('writer', text='作者')
  53. tree_view.heading('name', text='书名')
  54. tree_view.heading('novel_id', text='书ID')
  55. tree_view.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  56. # 展示界面
  57. root.mainloop()
复制代码
 
效果展示

最后

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


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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4