从网上下载小说_keywords:python、multiprocess

  1 # -*- coding: utf-8 -*-
  2 __author__ = "YuDian"
  3 
  4 from multiprocessing import Pool  # Pool用来创建进程池
  5 import os, time
  6 from urllib import request  # 访问网页
  7 from bs4 import BeautifulSoup  # 第三方库,能更好的对HTML进行解析
  8 
  9 '''
 10     基本思路:1.从一个盗版小说网站上得到一些小说的名字和对应的链接;
 11              2.选定一本小说名,通过对应的链接得到小说的所有章节链接;
 12              3.通过所有所有的章节链接通过对每个章节的网页进行分析,得到小说正文。分别存在不同的文档中(使用多进程)
 13              4.将文档按顺序拼接,得到最终文档,删除中间文档。
 14 '''
 15 
 16 
 17 def download(head, filename, ProNum, start, end, PageLinks):  # 向函数传入请求头、文件名、进程序号、始末章节、章节链表
 18     print(os.getpid())  # 打印该进程id
 19     for page in range(start, end + 1):
 20         PageUrl = PageLinks[page]
 21         PageReq = request.Request(PageUrl, headers=head)
 22         response = request.urlopen(PageReq)
 23         PageHtml = BeautifulSoup(response, 'lxml')
 24 
 25         title = PageHtml.find('div', class_='entry-single').h1.string  # 分析得到小说标题
 26         print(title, 'is downloading...')
 27         print(os.getpid())
 28         if page == start:
 29             f = open(filename + str(ProNum) + '.txt', 'w')  # 小说名+进程序号作为文件名
 30             f.write('\n' + title + '\n')
 31         else:
 32             f = open(filename + str(ProNum) + '.txt', 'a')
 33             f.write('\n' + title + '\n')
 34         text = PageHtml.find('div', id='booktext').children
 35         for i in text:
 36             if (i.find('div') == -1):
 37                 if len(i) > 1:
 38                     newstr = str(i).replace('\n', '').replace('\xa0', ' ').replace('\ue810', '').replace('\ue420',
 39                                                                                                          '').replace(
 40                         '\ue2f0', '').replace('\ue0df', '')  # 根据输出的情况手动将不能编码的字符进行转换
 41                     try:  # 保证在遇到不能打印的字符时,程序能进行运行。
 42                         f.write(newstr)
 43                     except Exception as e:
 44                         print(e)
 45 
 46 # 第一步:从网站上得到所有的小说名字和对应链接
 47 
 48 if __name__ == '__main__':
 49     AllLinks = {}  # AllLinks用来存放小说名称和对应链接
 50     url = r'http://www.kushubao.com/xiaoshuodaquan/3.html'  # 网站网址
 51     HeadUrl = r'http://www.kushubao.com'  # 因为从网址上爬到的小说链接只有后面的/xxxx所以要自己补全URL。
 52     head = {}  # 以浏览器的方式进行访问
 53     head[
 54         'User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'
 55     req = request.Request(url, headers=head)
 56     response = request.urlopen(req)  # 返回的response通过response.read().decode('uth-8')就可以输出网页的HTML
 57     html = BeautifulSoup(response, 'lxml')  # 将response变为BeautifulSoup能处理的对象
 58     novellist = html.find(class_='novellist')  # 定位到小说名和对应链接在的地方
 59     novels = novellist.find_all('a')  # 得到所有的小说名和链接在的HTML语句,.find_all()方法得到的是一个list
 60     for novel in novels:
 61         AllLinks[novel.string] = str(HeadUrl + novel.get('href'))
 62 
 63     # 第一步到这里结束。此时所有的小说名和对应的完整链接都存放在名为AllLinks的字典中。
 64     #
 65     # 第二步:通过指定小说名,从AllLinks中得到该小说的对应链接,然后下载所有的小说章节。
 66 
 67     name = '神灵契约'  # 指定的小说名称
 68     NovelUrl = AllLinks[name]
 69     NovelReq = request.Request(NovelUrl, headers=head)
 70     PageLinks = []  # 列表,用来存放所有的小说章节链接。
 71     # 不用字典的理由:因为元素在字典里面是无序排列的,在第三步要按顺序从低章到高章下载。所以直接用了一个list。反正章节名可以在没章里面搞到。
 72     response = request.urlopen(NovelReq)
 73     html = BeautifulSoup(response, 'lxml')  # html 中放的就是有每章的名字和链接的BeautifulSoup对象。可以用html.pretty()进行查看
 74     LinkTag = html.find('div', id='xslist')
 75     PageList = LinkTag.find_all('a')
 76     for page in PageList:
 77         PageLinks.append(NovelUrl + page.get('href'))
 78 
 79     # 自此,第二步结束,得到的章节链接仿真了PageLinks的链表中。
 80 
 81     # 第三步,多并程下载小说内容
 82 
 83     ProcessNumber = 11  # 要开的进程数
 84     p = Pool()  # 创建进程池。由于参数缺省,默认为运行电脑的核数
 85     StartTime = time.time()  # 开始时间
 86     StartPage = 0
 87     for process in range(ProcessNumber):  # 用来创建进程
 88         if (process < ProcessNumber - 1):
 89             EndPage = int(len(PageLinks) / ProcessNumber * (process + 1) - 1)
 90         else:
 91             EndPage = len(PageLinks) - 1
 92         #         得到每个进程下载起始章节。
 93         print('进程序号:', process + 1, '始末章节:%s--->%s' % (StartPage, EndPage))
 94         p.apply_async(download, args=(head, name, process, StartPage, EndPage, PageLinks))
 95         StartPage = EndPage + 1
 96     p.close()  # close和join要放到for循环外。
 97     p.join()
 98     EndTime = time.time()
 99     print('Total run time=%.3f' % (EndTime - StartTime))
100 
101     # 第三步结束。(download传入的参量太多了。)
102 
103     # 第4步:将所有分开的章节整合到一起,并删除临时章节。
104 
105     wr = open(name + '.txt', 'w')  # 最后存放的文件名
106     for i in range(ProcessNumber):
107         re = open(name + str(i) + '.txt', 'r')
108         lines = re.readlines()
109         wr.writelines(lines)
110         re.close()
111     wr.close()
112     # 文件合并完毕
113     for i in range(ProcessNumber):
114         try:
115             os.remove(name + str(i) + '.txt')  # 移除文件
116         except Exception as e:
117             print('文件:', name + str(i) + '.txt', '无法删除')

 

posted on 2018-03-23 11:54  我是人间惆怅客1  阅读(284)  评论(0)    收藏  举报

导航