一个简单的爬取小说的python程序 彻底搞懂Python的字符编码

第一个python程序,记录一下各种坑。

程序主要功能是爬取读书笔记网站(http://www.mossiella.com/)上的小说下载保存为txt,这里拿《明朝那些事》为例,网址为http://www.mossiella.com/xiandaiwenxue/mingchaonaxieshier/

如果想要爬取别的小说,只需要更改如下的变量即可:
初始化函数

def __init__(self):
		self.target = 'http://www.mossiella.com/xiandaiwenxue/mingchaonaxieshier/'     #保存要爬取的网址
		self.savefile  = '明朝那些事.txt'						#下载文件的名称
		self.dirclass  = 'booklist'							#目录div的class属性
		self.textclass = 'zwcent'							#正文div的class属性
		self.dirnames  = []								#保存目录的列表
		self.dirurl    = []								#保存每个目录的URL
		self.dirnums   = 0								#记录一共有多少章节

如下函数是获取小说的每个章节和每个章节的URL

def get_dirurl(self):
	code = requests.get(url = self.target).status_code
	if code is not 200:
		print('请求失败,请检查网络或者URL!')
		return
	req = requests.get(url = self.target)
	req.encoding = 'UTF-8'
	bf = BeautifulSoup(req.text, "lxml")
	text = bf.find_all('div', class_ = self.dirclass)
	for each in text:
		dir_bf = BeautifulSoup(str(each), "lxml")
		title = dir_bf.find_all('a')
		for each in title:
			self.dirnames.append(each.string)
			self.dirurl.append(each.get('href'))
			self.dirnums += 1
req = requests.get(url = self.target)

requests是python实现的简单易用的HTTP库,主要函数如下:

# 引入Requests库
import requests
# 发起GET请求
response = requests.get('https://www.baidu.com/')
# 查看响应类型 requests.models.Response
print(type(response))
# 输出状态码
print(response.status_code)
# 输出响应内容类型 text
print(type(response.text))
# 输出响应内容
print(response.text)
# 输出cookies
print(response.cookies)

# 发起POST请求
requests.post('http://httpbin.org/post')
# 发起PUT请求
requests.put('http://httpbin.org/put')
# 发起DELETE请求
requests.delete('http://httpbin.org/delete')
# 发送HEAD请求
requests.head('http://httpbin.org/get')
# 发送OPTION请求
requests.options('http://httpbin.org/get')

req.encoding = 'UTF-8'

因为我的python版本是是2.7版本,默认编码是ASCII码,要转换为UTF-8。具体编码问题可以看

彻底搞懂Python的字符编码

可以通过如下命令查看python版本号和默认编码

[root@localhost csdn-spider-master]# python 
Python 2.7.5 (default, Nov 20 2015, 02:00:19) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> print platform.python_version()
2.7.5
>>> import sys
>>> print sys.version
2.7.5 (default, Nov 20 2015, 02:00:19) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]
>>> print sys.version_info

sys.version_info(major=2, minor=7, micro=5, releaselevel='final', serial=0)

>>> import sys
>>> sys.getdefaultencoding()
'ascii'

bf = BeautifulSoup(req.text, "lxml")
text = bf.find_all('div', class_ = self.dirclass)
BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库,具体使用方法可以查看官方文档

for each in text:
		dir_bf = BeautifulSoup(str(each), "lxml")
		title = dir_bf.find_all('a')
		for each in title:
			self.dirnames.append(each.string)
			self.dirurl.append(each.get('href'))
			self.dirnums += 1

这段代码是循环获取并保存每个章节的名称和每个章节的URL

我们抓取的html源代码的部分内容如下

如下函数抓取每个章节的正文

def get_context(self):
	print(dl.savefile + '开始下载!')
	fd = open(self.savefile, 'a')
	for i in range(self.dirnums):
		req = requests.get(url = self.dirurl[i])
		req.encoding = 'UTF-8'
		bf = BeautifulSoup(req.text, "lxml")
		text = bf.find_all('div', class_ = self.textclass)
		ss = re.sub(r'\s+','',str(text[0]))
		st = re.findall('><p>(.*?)</p><divclass',ss,re.S)
		if len(st) > 0:
			sw = re.sub(r'<p>','',str(st[0]))
			sy = re.sub(r'</p>', '\n   ',sw)
		else:
			print('no data')
			continue
		fd.write(self.dirnames[i] + '\n')
		fd.write(sy + '\n\n')
		sys.stdout.write("  已下载:%.2f%%" %  float((float(i)/float(self.dirnums))*100) + '\r')
		sys.stdout.flush()
	fd.close()
	print(dl.savefile + '下载完成!')

抓取的正文html文件如下

我们需要去掉很多不需要的内容用re 模块中的sub函数即可实现。

ss = re.sub(r'\s+','',str(text[0]))
st = re.findall('><p>(.*?)</p><divclass',ss,re.S)

Re库是Python的标准库,主要用于字符串匹配。sub函数在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串。

re库中采用raw string类型表示正则表达式,表示为:r'text'。raw string是不包含对转义字符再次转义的字符串。\s表示匹配任何空白字符:[<空格>\t\r\n\f\v],+ 表示匹配一次或者多次,.表示匹配任意除换行符"\n"外的字符,*表示匹配前一个字符0或多次,?表示匹配一个字符0次或1次。re.S表示使.匹配包括换行在内的所有字符。上面两句话的作用是将所有的空格换行的空白字符替换为空,然后找出><p>和</p><divclass之间的所有字符。之后将处理之后的文字去掉<p>和</p>写进文件。

程序入口main函数

if __name__ == "__main__":

	dl = download()
	dl.get_dirurl()
	dl.get_context()

执行效果:





猜你喜欢

转载自blog.csdn.net/u014608280/article/details/80896116
今日推荐