WPS,我的阅读小说工具

前言:

原标题----运用Python多线程爬虫下载纵横中文网上的小说

这篇博文之所以取一个这样的标题,除了是想吸引读者的眼球之外,更重要的是最后的确实在wps等工具上阅读小说的。

1.做这个项目所需要的模块

python自带模块:os、threading
需要额外安装的模块:bs4、urllib、requests
怎样安装:
bs4 :pip install bs4
requests:pip install requests
urllib:pip install urllib3

2.怎样实现

2.1.得到小说的网址

我们首先要进入这个网址:
http://www.zongheng.com/
在搜索框中输入自己想看的小说的类型,点击搜索
如下:我输入的是 三国
在这里插入图片描述
这就是匹配到的小说名称了。
我们点击其中一本小说进入来到这个界面:
在这里插入图片描述
可以发现,这个界面的网址为:http://book.zongheng.com/book/591854.html
回到原来的那个界面,点击鼠标右键,然后点击检查,我们可以发现这个网址在上一个网址的这里。
在这里插入图片描述
代码:

def matching_book(): # 得到所有匹配到的小说
    keyword = input('请输入你想下载的小说标题:')
    key_word = parse.urlencode({'keyword': keyword})
    url='http://search.zongheng.com/s?%s'%(key_word)
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
    html=requests.get(url=url,headers=headers)
    info=html.text     # 网页信息
    soup=BeautifulSoup(info,'lxml')
    list_1=soup.select('div.search-tab>div.search-result-list.clearfix')   # 小说信息
    book_url=[]
    book_name=[]
    for i in range(len(list_1)):
        str_1=list_1[i].select('div.fl.se-result-infos>h2>a')[0]['href']       # 小说的网址
        name_1=list_1[i].select('div.fl.se-result-infos>h2>a')[0].get_text()   # 匹配到的小说名称
        book_url.append(str_1)
        book_name.append(name_1)
        print('【{}】-{}'.format(i+1,name_1))

    id=int(input('请输入你想看的小说序号:'))

    return book_url[id-1],book_name[id-1]

这样我们就得到了自己想看的小说网址了。

2.2. 得到小说目录的网址

我们来到这个界面,跟上面一样,进行检查。
发现这个网址在div.fr.link-group>a.all-catalog里面
在这里插入图片描述
为了使读者对这篇小说更加理解,也可以将小说的简介和类型也爬取下来。
代码:

def get_catalog_url(url):

    def get_info(list_1):
        str_1=''
        for html_1 in list_1:
            str_1+=html_1.get_text()+','
        return str_1

    # url='http://book.zongheng.com/book/591854.html'
    html_1=requests.get(url=url)
    info_1=html_1.text
    soup_1=BeautifulSoup(info_1,'lxml')
    info_book=soup_1.select('div.book-info')
    book_label_1=get_info(info_book[0].select('div.book-label>a'))
    book_label_2=get_info(info_book[0].select('div.book-label>span>a'))
    book_label=book_label_1+book_label_2
    jian_jie=(info_book[0].select('div.book-dec.Jbook-dec.hide>p'))[0].get_text()   #小说的简介
    book_mu_url=info_book[0].select('div.btn-group>div.fr.link-group>a.all-catalog')[0]['href']   # 小说目录的网址
    print('---->{}'.format(book_label))
    print('---->{}'.format(jian_jie))

    return book_mu_url

代码中需要传入的url就是上面2.1得到那个url

2.3.得到小说所有章节的网址

我们点击全部目录,来到这个界面,我们只需将这个界面里的所有小说章节的网址爬到,并进入这个网址就可以得到自己想看的小说内容了。
在这里插入图片描述
代码:

def get_catalog(url):
    # url='http://book.zongheng.com/showchapter/591854.html'
    headers_1={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
    html_2=requests.get(url=url,headers=headers_1)
    soup_2=BeautifulSoup(html_2.text,'lxml')
    list_3=soup_2.select('div.volume-list>div')
    title_list=[]
    ti_url_list=[]

    for soup_3 in list_3:
        info_text=soup_3.select('div.volume ')[0].get_text().strip('\n')  #去掉左右换行
        title_list.append(info_text)
        list_text=soup_3.select('ul.chapter-list.clearfix>li>a')
        for i in range(len(list_text)):
            list_text[i]=[list_text[i].get_text(),list_text[i]['href']]
        ti_url_list.append(list_text)

    for i in range(len(title_list)):
        print(title_list[i])
        for j in range(len(ti_url_list[i])):
            print(ti_url_list[i][j][0])

    return ti_url_list

这个函数跟上面一样,传入参数是2.2得到的那个网址,返回的是一个列表,也就是小说的所有章节的网址。

2.4 爬取小说所有章节的内容

我们随便点击其中的一章阅读,本来想跟上面一样,结果不行,在这个网址下无法按鼠标右键,不过,可以按F12,可以发现所有内容都在div.content下面的p标签里,我们只需爬取相应内容即可。
在这里插入图片描述

def Write_To_Wps(ti_url_list,book_name):
    def Thread_write(ti_url_list:list,book_name:str):
        while True:
            if len(ti_url_list)==0:
                break
            list_2=ti_url_list.pop()
            while True:
                if len(list_2)==0:
                    break
                url_text=list_2.pop()
                # url_1='http://book.zongheng.com/chapter/591854/38192586.html'
                url_1=url_text[-1]
                text_name=url_text[0]
                headers_1={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
                info_4=requests.get(url=url_1,headers=headers_1).text
                soup_4=BeautifulSoup(info_4,'lxml')
                text_info=soup_4.select('div.reader_box')
                # text_name=text_info[0].select('div.title>div.title_txtbox')[0].get_text()   #小说一章的标题
                list_1=text_info[0].select('div.content>p')    #小说一章的内容
                path_1='./{}'.format(book_name)
                try:
                    os.mkdir(path_1)
                except:
                    pass
                finally:
                    str_info=''
                    for str_1 in list_1:
                        str_info+=str_1.get_text()+'\n'
                    path_2=path_1+'/{}.doc'.format(text_name)
                    print('当前线程为{1},正在下载{0}'.format(text_name,threading.current_thread().getName()))
                    text_name=' '*30+text_name+'\n'
                    with open(path_2,'w',encoding='utf-8') as f:
                        f.write(text_name)
                        f.write(str_info)

    threading_list=[]
    for i in range(10):
        threading_1=threading.Thread(target=Thread_write,args=(ti_url_list,book_name,))
        threading_1.start()
        threading_list.append(threading_1)
    for i in threading_list:
        i.join()
    print('------------下载完毕!当前线程为{}'.format(threading.current_thread().getName()))

这个函数传入的参数就是***2.3***得到那个列表。
在这里,运用了多线程。不过,有个小问题,就是实际上用到的线程好像没有10个(原本创建了10个线程),不知道是不是我在代码中用到两个while循环的原因。

3.最终代码

import requests
from bs4 import BeautifulSoup
from urllib import parse
import os
import threading


def matching_book(): # 得到所有匹配到的小说
    keyword = input('请输入你想下载的小说标题:')
    key_word = parse.urlencode({'keyword': keyword})
    url='http://search.zongheng.com/s?%s'%(key_word)
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
    html=requests.get(url=url,headers=headers)
    info=html.text     # 网页信息
    soup=BeautifulSoup(info,'lxml')
    list_1=soup.select('div.search-tab>div.search-result-list.clearfix')   # 小说信息
    book_url=[]
    book_name=[]
    for i in range(len(list_1)):
        str_1=list_1[i].select('div.fl.se-result-infos>h2>a')[0]['href']       # 小说的网址
        name_1=list_1[i].select('div.fl.se-result-infos>h2>a')[0].get_text()   # 匹配到的小说名称
        book_url.append(str_1)
        book_name.append(name_1)
        print('【{}】-{}'.format(i+1,name_1))

    id=int(input('请输入你想看的小说序号:'))

    return book_url[id-1],book_name[id-1]

def get_catalog_url(url):

    def get_info(list_1):
        str_1=''
        for html_1 in list_1:
            str_1+=html_1.get_text()+','
        return str_1

    # url='http://book.zongheng.com/book/591854.html'
    html_1=requests.get(url=url)
    info_1=html_1.text
    soup_1=BeautifulSoup(info_1,'lxml')
    info_book=soup_1.select('div.book-info')
    book_label_1=get_info(info_book[0].select('div.book-label>a'))
    book_label_2=get_info(info_book[0].select('div.book-label>span>a'))
    book_label=book_label_1+book_label_2
    jian_jie=(info_book[0].select('div.book-dec.Jbook-dec.hide>p'))[0].get_text()   #小说的简介
    book_mu_url=info_book[0].select('div.btn-group>div.fr.link-group>a.all-catalog')[0]['href']   # 小说目录的网址
    print('---->{}'.format(book_label))
    print('---->{}'.format(jian_jie))

    return book_mu_url


def get_catalog(url):
    # url='http://book.zongheng.com/showchapter/591854.html'
    headers_1={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
    html_2=requests.get(url=url,headers=headers_1)
    soup_2=BeautifulSoup(html_2.text,'lxml')
    list_3=soup_2.select('div.volume-list>div')
    title_list=[]
    ti_url_list=[]

    for soup_3 in list_3:
        info_text=soup_3.select('div.volume ')[0].get_text().strip('\n')  #去掉左右换行
        title_list.append(info_text)
        list_text=soup_3.select('ul.chapter-list.clearfix>li>a')
        for i in range(len(list_text)):
            list_text[i]=[list_text[i].get_text(),list_text[i]['href']]
        ti_url_list.append(list_text)

    for i in range(len(title_list)):
        print(title_list[i])
        for j in range(len(ti_url_list[i])):
            print(ti_url_list[i][j][0])

    return ti_url_list


def Write_To_Wps(ti_url_list,book_name):
    def Thread_write(ti_url_list:list,book_name:str):
        while True:
            if len(ti_url_list)==0:
                break
            list_2=ti_url_list.pop()
            while True:
                if len(list_2)==0:
                    break
                url_text=list_2.pop()
                # url_1='http://book.zongheng.com/chapter/591854/38192586.html'
                url_1=url_text[-1]
                text_name=url_text[0]
                headers_1={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'}
                info_4=requests.get(url=url_1,headers=headers_1).text
                soup_4=BeautifulSoup(info_4,'lxml')
                text_info=soup_4.select('div.reader_box')
                # text_name=text_info[0].select('div.title>div.title_txtbox')[0].get_text()   #小说一章的标题
                list_1=text_info[0].select('div.content>p')    #小说一章的内容
                path_1='./{}'.format(book_name)
                try:
                    os.mkdir(path_1)
                except:
                    pass
                finally:
                    str_info=''
                    for str_1 in list_1:
                        str_info+=str_1.get_text()+'\n'
                    path_2=path_1+'/{}.doc'.format(text_name)
                    print('当前线程为{1},正在下载{0}'.format(text_name,threading.current_thread().getName()))
                    text_name=' '*30+text_name+'\n'
                    with open(path_2,'w',encoding='utf-8') as f:
                        f.write(text_name)
                        f.write(str_info)

    threading_list=[]
    for i in range(10):
        threading_1=threading.Thread(target=Thread_write,args=(ti_url_list,book_name,))
        threading_1.start()
        threading_list.append(threading_1)
    for i in threading_list:
        i.join()
    print('------------下载完毕!当前线程为{}'.format(threading.current_thread().getName()))


if __name__ == '__main__':
    tuple_1=matching_book()    # 这个返回的是一个元组,第一个参数是小说的网址,第二个参数是小说的名称
    url,book_name=tuple_1[0],tuple_1[1]
    catalog_url=get_catalog_url(url)    #小说目录的url
    ti_url_list=get_catalog(catalog_url)
    Write_To_Wps(ti_url_list=ti_url_list,book_name=book_name)

运行结果:
在这里插入图片描述
这个运行完之后,可以发现在当前文件夹下面多了一个文件夹,文件夹的名称就是自己选的小说名称,所下载的小说章节就在这个文件夹下面。
在这里插入图片描述
感觉这个效果好像不是很好,为了更加清晰看到自己下载的总章节和方便阅读,我们可以执行一下这个代码:

import os

path_1=input('输入路径:')
list_1=os.listdir(path_1)
dict_1 = {
    '一': '1',
    '二': '2',
    '三': '3',
    '四': '4',
    '五': '5',
    '六': '6',
    '七': '7',
    '八': '8',
    '九': '9',
    '零': '0'
}
list_2=[]
for i in range(len(list_1)):
    str_1=list_1[i][list_1[i].find('第')+1:list_1[i].find('章 ')]
    for j in dict_1:
        str_1=str_1.replace(j,dict_1[j])

    if '十' in str_1:
        if len(str_1) == 1:
            str_1 = '10'
        elif str_1[-1]=='十':
            str_1=str_1.replace('十','0')
        elif str_1[0]=='十':
            str_1=str_1.replace('十','1')
        else:
            str_1=str_1.replace('十','')

    if '百' in str_1:
        if len(str_1)==2:
            str_1=str_1.replace('百','00')
        else:
            str_1=str_1.replace('百','')

    str_1=list_1[i].replace(list_1[i][list_1[i].find('第')+1:list_1[i].find('章 ')],str_1)

    list_2.append(str_1)

for i in range(len(list_1)):
    print(list_1[i],list_2[i])
    os.rename(path_1+'\\'+list_1[i],path_1+'\\'+list_2[i])

运行结果:
在这里插入图片描述
在这里插入图片描述

4.改进与总结

  1. 也许是访问次数过多的原因,服务器会封掉我们的ip地址,如果讲改进的话,希望用到代理ip;
  2. 有一些小说因为章节名称的原因,会包错,这个解决我已经在最终代码上进行改进了,但在2.4那里没有改,希望大家谅解;
  3. 本代码仅供娱乐和学习,切莫用于商业,一经发现,概不负责!
  4. 因为有的小说部分章节需要登陆,才能阅读所有内容,所以这些章节最终爬取得到的内容只有一点点,不知道大家有什么好的改进措施吗?欢迎留言。
发布了51 篇原创文章 · 获赞 299 · 访问量 9172

猜你喜欢

转载自blog.csdn.net/qq_45404396/article/details/105009922