既然我们之前已经讲了BeautifulSoup的使用,那么我们今天就来实战下,用BeautifulSoup解析小说网站,做一个小说下载器;
首先,先分析一下网站:
- 我们的目标是一个叫全小说的网站:https://qxs.la/
我们可以看见右上角的位置有一个搜索框,我们可以将想要搜索的关键词键入,然后搜索我们想要的内容,我们来分析下这个网站的结构; - 我们在搜索框输入“唐家三少”,看看网页会发生怎么样的变化:
网页把站内所有唐三的小说都搜索出来了,最新的小说都有,看来这个网站还是更新挺勤的;回过头来分析下页面,没有打开新的网页,但是打开了一个新的页面:我们发现变化的是在原网址后面加上了 "/s_***"
我们搜索另外一个,看看这个发现成不成立:
我们发现这个想法貌似是对的,搜索的内容页面就是在原址的基础上加上了 "/s_***" - 我们随便点开一个,看看对应的页面内容是怎么样的:
我们发现小说的所有章节都在这里面了,我们来检查一下源码,看下网页的结构是怎么设计的:
发现所有的章节都在 <div class="chapters"> 标签下面,但是客气的是竟然有几章凑数的章节,这个我们先不管,我们打开第一章,看看里面的分布; - 小说的内容已经有了,我们可以看见最下面有下一章,那么我们是不是可以通过这个下一章链接进行翻页,这样就不用获取所有页面的网址了
好了,我们现在已经分析好了,接下来就是开始来写代码了,既然是小说下载器,那么肯定要有一个界面是不是:
- 有一个输入框,接收我们想要搜索的关键字
- 要有一个列表框,显示我们搜索出来的结果
- 当我们选择小说,单击下载按钮的时候,就开始下载这本小说,生成txt文档
设计小说下载器界面:
from tkinter import *
window = Tk()
window.geometry('300x500')
window.title('小说下载器')
Label(window,text='请输入你想搜索的内容:',font=('楷体',12)).place(x=10,y=10)
# 输入框
key_word = Entry(window,font=('楷体',16),width=25)
key_word.place(x=10,y=35)
# 显示列表
show = Listbox(window,width=25,height=15,font=('楷体',16))
show.place(x=10,y=80)
# 搜索按钮
def seek():
print('')
Button(window,text='搜索',font=('楷体',16),command=seek).place(x=10,y=430)
# 下载按钮
def download():
print('')
Button(window,text='下载',font=('楷体',16),command=download).place(x=120,y=430)
# 退出按钮
Button(window,text='退出',font=('楷体',16),command=quit).place(x=228,y=430)
window.mainloop()
第二步,实现小说搜索的功能
def seek():
global info
book = []
author = []
add = []
word = key_word.get() # 获取输入框的内容
url = 'https://qxs.la/s_' + word # 拼接搜索地址
bs = get_html_bs(url) # 获取源码并返回bs对象
data_all = bs.find_all('ul',class_='list_content') # 搜索所有的小说
for data in data_all: # 遍历提取信息
book.append(data.find_all('a')[0].string) # 提取小说名字
add.append(data.find_all('a')[0]['href']) # 提取小说地址
author.append(data.find_all('a')[2].string) # 提取小说作者
info = list(zip(book,author,add)) # 将提取出来的信息打包
for i in range(show.size()): # 清空所有的列表项
show.delete(0)
for data in info: # 将信息插入到列表中,显示内容
show.insert('end','{}({})'.format(data[0],data[1]))
Button(window,text='搜索',font=('楷体',16),command=seek).place(x=10,y=430)
第三步,实现小说下载功能:
def download():
global info # 导入全局变量
txt = '' # 存放小说内容
index = show.curselection()[0] # 获取选中列表项的下标
book_name = info[index][0] # 提取书名
url = 'https://qxs.la' + info[index][2] # 合成小说详情页面地址
bs = get_html_bs(url) # 获取源码并返回bs对象
first = bs.find('div',class_="chapter") # 提取出第一篇小说的地址
url = 'https://qxs.la' + first.find('a')['href'] # 合成地址
while True:
try:
bs = get_html_bs(url) # 获取小说内容页面
txt = txt + bs.find('div',class_="text t_c").h1.text + '\n' # 保存章节题目
data = bs.find('div', id="content") # 提取小说内容
data = data.find_all(text=True) # 因为这个页面比较特殊,大标签内包括小标签和文本内容
# 所以要经过进一步的处理,先获取全部文本内容
for d in data: # 遍历所有获取到的内容
if d[0:2] == u'\u3000\u3000': # 发现小说内容都有两个空格开头
txt = txt + d.strip() + '\n' # 将小说内容拼起来
print('{}下载完毕!'.format(url)) # 输出下载结果
next_url = bs.find('a', id="nextLink")['href'] # 获取下一章的地址
if next_url[0:5] == '//qxs': # 发现最后一张还是有下一章的,但是下一章的地址是以“//qxs”开头
print('下载完毕!')
break
url = 'https://qxs.la' + next_url # 拼接下一章的地址
except:
print('下载错误!')
txt.encode('utf-8') # 设置文字编码
with open('{}.txt'.format(book_name),'w') as f: # 保存小说,生成txt文档
f.write(txt)
Button(window,text='下载',font=('楷体',16),command=download).place(x=120,y=430)