使用python抓取liaoxuefeng网站正文和目录
2017-02-24 09:46
531 查看
本文档参考了该博客和其源代码
不过为了方便,我没有使用beautifulsoup和pdfkit,而是直接通过python自带的HTMLParser来处理html,然后解析出html中的主体内容,然后重新生成一个新的html,并重命名为章节内容。
首先我们看一下廖雪峰python的网页结构
分为:目录、正文、其他。对于我们有用的信息都在目录和正文中,而且目录我们只需要解析一次,因为各个页面中的目录都是一样的。
所以我们的解析思路是这样的:
1. 从第一页中解析目录,提取目录各项名称和对应的url地址,分别保存到两个列表中,即titleList和addrList
2. 创建一个以titleList中各项为文件名的html文件并打开,将文件名写入文件开头作为标题,
3. 依次次访问addrlist中对应的各个网页,提取网页中的正文部分,并将正文部分内容写入到之前打开的文件中,同时规划好各个部分的格式。
首先通过urllib.response的函数来获取网页内容,然后我们创建一个hp对象来处理读取的html文档内容。
对于hp类是继承自HTMLParser类的,同时需要重载HTMLParser的三个函数handle_starttag、handle_endtag和handle_data
当检测到节点头时,就会触发handle_starttag的调用,例如
当检测到节点尾时,就会触发handle_endtag的调用,例如
当检测到其他内容是会调用handle_data,这个通常来处理节点头和节点尾之间的文本节点,例如
另外节点头中通常包含有属性值,这些值通常在调用handle_starttag是通过attr这样的一个元组序列来保存传递的。
于是,当我们需要判断某一个节点头中是否包含我们需要的属性值是,我们就需要遍历这个attr,比如有这样一个代码:
判断该段代码头是否class=”start”
为了方便使用我们将它写成一个函数
通过查看F12开发者模式我们可以发现,目录页面是包含在**第二个**class=”uk-nav uk-nav-side”的
同时正文内容包含在第一个class=”x-wiki-content”的
首先我们通过urllib.request.urlopen访问
网址,这个网址是廖雪峰python教程的第一个网页,因为刚才说过每个页面中的目录内容都是相同的,所以我们通过访问第一个页面即可提取出目录内容。
然后通过response.read()来读取网页内容。
然后定义了一个继承自HTMLParser的hp类,同时定义了hp对象来解析网页内容。
我们来看看hp类的原理。
首先我们在handle_starttag函数中来匹配class=”uk-nav uk-nav-side”的类,由于这样的类有两个,我们要匹配第二个,所以在self.cnt=2的时候设置匹配成功标志self.classGroup=True,其他的正文获取都是在匹配成功的前提下来进行操作的
c3be
,所以都会有if self.classGroup== True的条件判断,通过观察网页内容,我们可以知道通过判断ul的结束符即可判断class=”uk-nav uk-nav-side”的结束,而在handle_data函数中,我们就需要将读取到的内容保存到titleList,而地址实在节点头的href属性中的。
首先我们需要遍历titleList和addrList
然后根据titleList的内容在本地新建一个html文件,并写入titleList的内容作为标题
接着访问addrList对应的网页,并获取网页内容,预先定义好一个继承自HTMLParser的webContext类,通过这个类的对象来解析正文网页,并将正文按照相应的格式写入html文件中。
然后我们看看webContext类
handle_starttag负责节点头的处理和属性处理
首先匹配class=”x-wiki-content”,查找到正文的开始地方。查找到第一个即表明匹配成功self.contextFlag=True。然后将节点头内容写入本地的html文件中,需要做特殊处理的就是img节点头。这个节点头的格式是这样的
好了整个思路就是这样的,下面是运行效果
运行截图
保存截图
预览截图
完整源码
笔记:
变量的作用域
全局变量和局部变量以及global关键字
文件操作
全局变量与None
urllib库使用
HTMLParser工作机制
网页访问机制
html dom文档结构
不过为了方便,我没有使用beautifulsoup和pdfkit,而是直接通过python自带的HTMLParser来处理html,然后解析出html中的主体内容,然后重新生成一个新的html,并重命名为章节内容。
首先我们看一下廖雪峰python的网页结构
分为:目录、正文、其他。对于我们有用的信息都在目录和正文中,而且目录我们只需要解析一次,因为各个页面中的目录都是一样的。
所以我们的解析思路是这样的:
1. 从第一页中解析目录,提取目录各项名称和对应的url地址,分别保存到两个列表中,即titleList和addrList
2. 创建一个以titleList中各项为文件名的html文件并打开,将文件名写入文件开头作为标题,
3. 依次次访问addrlist中对应的各个网页,提取网页中的正文部分,并将正文部分内容写入到之前打开的文件中,同时规划好各个部分的格式。
从首页中获取目录信息
def get_url_list(): """ 获取所有URL目录列表 :return: """ response = urllib.request.urlopen("http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000") htmlcontext=response.read().decode("UTF-8") myHp=hp() myHp.feed(htmlcontext) myHp.close()
首先通过urllib.response的函数来获取网页内容,然后我们创建一个hp对象来处理读取的html文档内容。
对于hp类是继承自HTMLParser类的,同时需要重载HTMLParser的三个函数handle_starttag、handle_endtag和handle_data
当检测到节点头时,就会触发handle_starttag的调用,例如
<div>
当检测到节点尾时,就会触发handle_endtag的调用,例如
</div>
当检测到其他内容是会调用handle_data,这个通常来处理节点头和节点尾之间的文本节点,例如
<div>ABC</div>中的ABC
另外节点头中通常包含有属性值,这些值通常在调用handle_starttag是通过attr这样的一个元组序列来保存传递的。
于是,当我们需要判断某一个节点头中是否包含我们需要的属性值是,我们就需要遍历这个attr,比如有这样一个代码:
<div class="start"> python教程 </div>
判断该段代码头是否class=”start”
for each in attr: if class == each[0] and "start"== each[1]: return True return False
为了方便使用我们将它写成一个函数
#属性匹配 def findattr(attr,name,val): for each in attr: if name == each[0] and val == each[1]: return True return False
通过查看F12开发者模式我们可以发现,目录页面是包含在**第二个**class=”uk-nav uk-nav-side”的
<div>标签中
同时正文内容包含在第一个class=”x-wiki-content”的
<div>标签中
目录提取
def get_url_list(): """ 获取所有URL目录列表 :return: """ response = urllib.request.urlopen("http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000") htmlcontext=response.read().decode("UTF-8") myHp=hp() myHp.feed(htmlcontext) myHp.close()
首先我们通过urllib.request.urlopen访问
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
网址,这个网址是廖雪峰python教程的第一个网页,因为刚才说过每个页面中的目录内容都是相同的,所以我们通过访问第一个页面即可提取出目录内容。
然后通过response.read()来读取网页内容。
然后定义了一个继承自HTMLParser的hp类,同时定义了hp对象来解析网页内容。
我们来看看hp类的原理。
class hp(HTMLParser): classTag =False classGroup = False listTag = False cnt = 0 def handle_starttag(self,tag,attr): self.classTag=findattr(attr,"class","uk-nav uk-nav-side") if self.classTag== True: self.cnt=self.cnt+1 if self.cnt==2: self.classGroup=True if self.classGroup== True: if tag == 'a': self.listTag = True #print (dict(attr)) for each in attr: if each[0] == 'href': #print(each[1]) addrList.append(each[1]) def handle_endtag(self,tag): if self.classGroup== True: if tag == 'a': self.listTag = False if tag == 'ul': self.classGroup=False def handle_data(self,data): if self.classGroup == True and self.listTag == True: #print (data) titleList.append(data)
首先我们在handle_starttag函数中来匹配class=”uk-nav uk-nav-side”的类,由于这样的类有两个,我们要匹配第二个,所以在self.cnt=2的时候设置匹配成功标志self.classGroup=True,其他的正文获取都是在匹配成功的前提下来进行操作的
c3be
,所以都会有if self.classGroup== True的条件判断,通过观察网页内容,我们可以知道通过判断ul的结束符即可判断class=”uk-nav uk-nav-side”的结束,而在handle_data函数中,我们就需要将读取到的内容保存到titleList,而地址实在节点头的href属性中的。
获取目录对应的正文页。
接下来我们就要解析之前获取到的addrList各个地址的内容,套路跟获取目录差不多。首先我们需要遍历titleList和addrList
for i in range(len(titleList)):
然后根据titleList的内容在本地新建一个html文件,并写入titleList的内容作为标题
filename=titleList[i].replace('/','_') #titleList中的内容会用来作为文件名,所以首先需要替换文件名不支持的字符 filename=filename.replace('-','_') currentPath='%s\\%d_%s.html' %(os.path.dirname(__file__),i,filename) print(currentPath) currentFile=open(currentPath,'w') temp='<h1>%s</h1>\r\n' %(titleList[i]) #写入标题 currentFile.write(temp)
接着访问addrList对应的网页,并获取网页内容,预先定义好一个继承自HTMLParser的webContext类,通过这个类的对象来解析正文网页,并将正文按照相应的格式写入html文件中。
req = urllib.request.Request('http://www.liaoxuefeng.com'+addrList[i]) try: response = urllib.request.urlopen(req) except HTTPError as e: print('The server couldn\'t fulfill the request.') print('Error code: ', e.code) except URLError as e: print('We failed to reach a server.') print('Reason: ', e.reason) else: print("good!") req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.2; rv:16.0) Gecko/20100101 Firefox/16.0') req.add_header('Connection','keep-alive') htmlcontext=response.read().decode("UTF-8") htmlFile=webContext() htmlFile.feed(htmlcontext) htmlFile.close()
然后我们看看webContext类
handle_starttag负责节点头的处理和属性处理
def handle_starttag(self,tag,attr): self.classTag=findattr(attr,"class","x-wiki-content") #匹配x-wiki-content类 if self.classTag == True: self.cnt=self.cnt+1 self.contextFlag=True if self.contextFlag==True: temp='<%s ' %(tag) imgsrc='' for each in attr: if tag=='img' and each[0] == 'src': #each为元组,元组拥有不可变性 if(each[1].find('http')!=0): imgsrc='http://www.liaoxuefeng.com%s' %(each[1]) else: imgsrc=each[1] temp=temp+each[0]+'='+imgsrc break #else: # temp=temp+each[0]+'='+each[1] if tag == 'img': temp=temp+'/>' else: temp=temp+'>' currentFile.write(temp)
首先匹配class=”x-wiki-content”,查找到正文的开始地方。查找到第一个即表明匹配成功self.contextFlag=True。然后将节点头内容写入本地的html文件中,需要做特殊处理的就是img节点头。这个节点头的格式是这样的
<img src="xxxxxxx"/>这个节点是只有节点头,没有节点尾,而且src对应的网址也有两种类型,一种绝对http型,一种相对本站性,相对本站性需要加上站头’http://www.liaoxuefeng.com‘来形成完整的图片地址。然后在handle_data中解析并保存正文内容
def handle_data(self,data): if self.contextFlag == True: currentFile.write(data)
好了整个思路就是这样的,下面是运行效果
运行截图
保存截图
预览截图
完整源码
笔记:
变量的作用域
全局变量和局部变量以及global关键字
文件操作
全局变量与None
urllib库使用
HTMLParser工作机制
网页访问机制
html dom文档结构
相关文章推荐
- 使用python抓取网站信息
- 深度剖析使用python抓取网页正文的源码
- Python使用scrapy抓取网站sitemap信息的方法
- 求助,如何使用Python3 抓取ASPX网站中翻页URL不改变的网页内容呢?求指导!谢谢!
- Python抓取优酷视频(下):使用web.py搭建网站框架
- 使用python来批量抓取网站图片
- Python使用代理抓取网站图片(多线程)
- 使用Python制作获取网站目录的图形化程序
- 【实例】python 使用beautifulSoup 抓取网页正文 以淘宝商品价格为例
- 使用python抓取网站代码,并下载里面的url
- 深度剖析使用python抓取网页正文的源码
- 按示例学python:使用python抓取网页正文
- 使用Python下载整个网站的连接,适合能目录浏览的网站。
- 使用python抓取网页
- 黄聪:使用 Python 登录网站
- python程序使用pyinstaller打包成单一.exe文件后,如何的到.exe文件所在目录?
- 黄聪:使用Python中的HTMLParser、cookielib抓取和解析网页、从HTML文档中提取链接、图像、文本、Cookies(二)
- 黄聪:使用Python中的urlparse、urllib抓取和解析网页(一)
- 使用XSLT抓取网站内容抽取网页数据的技巧