赞
踩
最近想下载一些有声小说,但是苦于没有找到批量下载,每次都是单集单集的下载的,觉得很麻烦,就考虑用python写一个爬虫来实现自动搜集小说,自动下载。下面就是开始展开漫漫的爬虫之路。
基础的就不多说了,重点就是针对在项目中遇见的一些问题进行记录。主要就以下三个方面进行展开:
1.正则表达式的使用
2.编码格式
3.如何获取js动态加载生成的内容
1.正则表达式的使用
正则表达式主要是用于匹配相应的标签,这个可以快速定位出需要的标签,使爬虫更有效率。
如:
考虑使用如下正则表达式:
self.down_pattern = '<a title=.+? href=(.\/down.+?)target=.*?>.+?</a>'
一开始编写正则的时候,主要是刚开始使用,很多不是很熟悉,使用了\w来匹配,后来发现无法匹配,后来换成了.来匹配,同时使用了非贪婪匹配。非贪婪匹配就是在*+后加上?即可。具体的正则表达式相关的知识请参阅别的教程,总之正则是个很大很大的坑,日后还有再找机会慢慢填。
2.编码格式
编码格式也是个很恼火的问题,在编写爬虫爬取网页经常爆出unicodeencodeerror错误,几乎都是中文导致的影响,所以每次以后记住,如果网页中有中文出现,返回的响应用decode('gbk')或者decode('gb2312')解码,这样中文就可以显示正确了。同时如果在url中出现了中文,那么想当然也要进行相应的编码,可以使用urllib.parse.quote()来进行相应编码,一般默认utf-8,但在运用听书网的搜索功能时,发现它传入的中文转换成了gb2312格式,那么只需quote传入gb2312就行。这里也是当时费了一点时间,所以提醒自己日后一定要注意多种格式编码。后来借助一个在线编码转换网站,成功发现了它是转换成了gb2312,之前都是默认用的utf-8。这里安利一下这个网站,感觉方便的。http://tool.chinaz.com/tools/urlencode.aspx
3.获取js动态生成的内容
在编写自动下载小说的过程中发现,当我访问每个下载链接的主页的时候,我爬取不到下载的url,咦,当时就觉得很奇怪,查看了源之后发现确实没有写在源中,于是猜测可能是动态加载了,好吧,那就乖乖打开开发人员工具吧。之前有过爬取豆瓣排行榜的经历,所以首先想到的是xhr类型,返回一个json格式数据,后来发现并不是,接着查看了网页加载后的所有动态文件,发现一个叫down.js的文件有点意思啊,查看了它的响应结果,果真,就是下载地址。好吧,那么问题就来了,如果使用python3来爬取js动态加载的内容呢。这里就最简单的考虑了使用selenium+edge来模拟浏览器访问,等加载完成之后,再读取相应地址。这里呢安装selenium还是挺简单的,顺带还要下载一个edge的运行驱动吧,把驱动放在一个配置了path的目录下,这样似乎才可以正确调用浏览器。后面还要继续在学下selenium。
下面是全部代码:
- import urllib.request
- import urllib.parse
- import re
- import os.path
- import selenium.webdriver
-
- # <a title="第000章" href="/down/?26-0-0.html" target="_blank">第000章</a>
-
-
- class TingSpider:
- def __init__(self, bookname):
- self.down_pattern = '<a title=.+? href=(.\/down.+?) target=.*?>.+?</a>' # 匹配下载主页
- self.pattern = '<a title=.+? href=.+? target=.*?>(.+?)</a>' # 匹配章节名称
- self.hotpattern = '<a href=(.*?) title=.*>.*</a></h2>(\d*?)<b>' # 匹配书的热度的正则表达
- self.index_url = "http://www.520tingshu.com/search.asp?searchword=" # 搜索主页
- self.down_url_pattern = '<a href=(.+)\/.*\.mp3" target=.*?>.+?</a>' # 下载链接的地址
- self.bookname = bookname
-
- def __getmax(self, result): # 获取搜索的结果中热度最高的那本书
- max_item = None
- for i in range(len(result)):
- if max_item == None:
- max_item = result[i]
- elif int(result[i][1]) > int(max_item[1]):
- max_item = result[i]
- return max_item
-
- def __searchbook(self): # 获得要搜索的书的首页地址
- file = urllib.request.urlopen(self.index_url + urllib.parse.quote(self.bookname, encoding='gb2312'))
- data = file.read().decode('gbk')
- result = re.findall(self.hotpattern, data)
- if result is None:
- raise 'No book found'
- res = self.__getmax(result)
- new_url = "http://www.520tingshu.com"+res[0].replace('"', '')
- return new_url
-
-
- def __getlist(self): # 获得该有声小说所有的章节名,小说下载页的url
- bookurl = self.__searchbook()
- req = urllib.request.Request(bookurl)
- file = urllib.request.urlopen(req)
- data = file.read().decode('gbk')
- result = re.findall(self.pattern, data)
- tmp_url = re.search(self.down_pattern, data)
- return result, "http://www.520tingshu.com" + tmp_url.group(1).replace("'", '')
-
- def __getdownurl(self, downpage): # 获取下载链接地址的除去文件名的地址
- brower = selenium.webdriver.Edge()
- brower.get(downpage)
- brower.maximize_window()
- result = re.search(self.down_url_pattern, brower.page_source)
- brower.close()
- return result.group(1).replace('"', '') + '/'
-
- def __getAllUrl(self): # 获得所有的章节的下载地址
- url = []
- result, downpage = self.__getlist()
- down_url = self.__getdownurl(downpage)
- for item in result:
- tmp_url = down_url + item + ".mp3"
- url.append(urllib.request.quote(tmp_url, safe='/:?='))
- return url
-
- def down_file(self):
- result = self.__getAllUrl() # 所有的章节对应的下载地址
- for i in range(len(result)):
- s = str(i)+".mp3"
- if self.__exist(s) == False:
- self.__downfile(result[i], s)
-
- def __downfile(self, url, filename): # 将文件下载到本地
- file = urllib.request.urlopen(url)
- data = file.read()
- with open(filename, "wb") as f:
- f.write(data)
-
- def __exist(self, s):
- if os.path.exists(s):
- return True
- else:
- return False
-
-
- test = TingSpider("诛仙")
- test.down_file()
代码地址:https://github.com/xiaoHzp/python/blob/master/Ting_shu.py
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。