# novel_downloader.py
'''
从《笔趣看》网站下载小说:
1.定义一个下载类
2.调用类
'''
from bs4 import BeautifulSoup
import requests, sys
class downloader:
def __init__(self):
self.server = 'http://www.biqukan.com/' #网站url
self.target = 'http://www.biqukan.com/20_20952/' #章节目录url
self.titles = [] #章节名
self.urls = [] #每一章的网页url
self.nums = [] #下载的章数
def get_download_url(self):
req = requests.get(url=self.target) #获得response对象
html = req.text #获得html文件
div_bf = BeautifulSoup(html) #创建一个BeautifulSoup对象
div = div_bf.find_all('div', class_ = 'listmain') #筛选html文件内容,返回的是一个list
a_bf = BeautifulSoup(str(div[0])) #以list中的内容构建Beautiful对象
a = a_bf.find_all('a') #进一步筛选,返回一个多元素list
self.nums = len(a[12:]) #设置要下载的章节
for each in a[12:]:
self.titles.append(each.string) #将章节名存入一个列表
self.urls.append(self.server + each.get('href'))#将每章的url存入一个列表
def get_contents(self, chapter_url):
req = requests.get(url=chapter_url)
html = req.text
bf = BeautifulSoup(html)
contents = bf.find_all('div', class_ = 'showtxt')
contents = contents[0].text.replace('\xa0'*8, '\n\n')#选筛选出文字内容,再从中替换掉空格
return contents
def save_in(self, filename, title, contents):
with open(filename, 'a', encoding='utf-8') as f:
f.write(title + '\n')
f.writelines(contents)
f.write('\n\n')
if __name__ == '__main__':
d=downloader()
d.get_download_url()
print('《牧云天下》开始下载:')
for i in range(d.nums):
d.save_in('《牧云天下》.txt', d.titles[i], d.get_contents(d.urls[i]))
sys.stdout.write("已下载:%.3f%%" % float(100*i/d.nums) + '\r')
sys.stdout.flush()
print('下载完成!')
涉及到的几个知识点:
使用的第三方库
第一步,抓取网页html信息:**
使用了requests库中的requests.get(url)函数。
其中url为Uniform Resource Locator,即通常我们所说的网址。该函数返回一个response对象,利用该对象可以获取网页的数据。
(http://docs.python-requests.org/zh_CN/latest/user/quickstart.html)
第二步,解析并筛选html信息:
使用了BeautifulSoup库。
首先构建一个BeautifulSoup对象,然后调用find_all函数进行筛选。
该函数的参数可查看帮助文档。
(http://beautifulsoup.readthedocs.io/zh_CN/latest/)
with … as … 语句进行文件操作
with open("/tmp/foo.txt") as file:
data = file.read()
等价于:
file = open("/test.txt")
try:
data = file.read()
finally:
file.close()
可以看到前者更为简洁。
open函数的使用:
open(filename, ‘a’, encoding=’utf-8’)
这里‘a’表示以追加模式打开(必要时新建文件),从尾部写入数据;
encoding用来表示写入的数据的编码方式,对非UTF-8编码需要注明。
Write和Writelines的区别:
file.write(str)的参数是一个字符串,就是你要写入文件的内容.
file.writelines(sequence)的参数是字符序列,比如列表,它会迭代帮你写入文件。
参考博文:
open函数:http://www.cnblogs.com/dkblog/archive/2011/02/24/1980651.html
with… as…:http://www.cnblogs.com/ymjyqsx/p/6554817.html
显示下载进度的方法
这里调用了sys模块中的两个函数:
sys.stdout.write("已下载:%.3f%%" % float(100*i/d.nums) + '\r')
sys.stdout.flush() #用于缓冲
其中,
转义字符’\r’用来将光标返回本行行首。
write和print的区别是:print函数打印多行,而write打印单行。
编程中发现再windows命令行中可以实现,而再Python IDLE中’\r’被忽略了。不知道是什么原因。