Python正则表达式实战:构建内涵段子爬虫
本文详解如何利用Python正则表达式编写一个抓取内涵段子的爬虫程序。内容涵盖使用urllib2获取网页源码、通过正则表达式匹配特定HTML标签提取段子内容、处理中文编码乱码问题,以及将结果保存至本地文件。通过分步代码示例,展示从数据获取、筛选到持久化存储的完整流程。
Python正则表达式爬虫实战:从获取到保存
掌握正则表达式这一强大工具后,我们便能够对抓取到的所有网页源代码进行精准筛选。
接下来,我们将以爬取内涵段子网站为例,演示具体操作流程。
目标网址为:http://www.neihan8.com/article/list_5_1.html
访问该页面后,可以看到排列整齐的段子内容。在翻页过程中,请注意观察URL地址的变化规律。
- 第一页的URL为:http://www.neihan8.com/article/list_5_1.html
- 第二页的URL为:http://www.neihan8.com/article/list_5_2.html
- 第三页的URL为:http://www.neihan8.com/article/list_5_3.html
- 第四页的URL为:http://www.neihan8.com/article/list_5_4.html
通过观察可以发现,URL中仅页码参数发生变化。因此,要爬取所有段子,只需动态修改该参数即可。
下面我们将分步骤实现所有段子的爬取过程。
第一步:获取网页数据
第一步:获取数据
沿用之前的方法,我们需要编写一个用于加载页面的函数。
为此,我们统一定义一个类,将URL请求封装为该类的一个成员方法。
创建一个新的Python文件,命名为duanzi_spider.py。
在该文件中定义一个Spider类,并添加一个用于加载页面的成员方法。
import urllib2
class Spider:
"""
内涵段子爬虫类
"""
def loadPage(self, page):
"""
@brief 定义一个url请求网页的方法
@param page需要请求的第几页
@returns 返回的页面url
"""
url = "http://www.neihan8.com/article/list_5_" + str(page)+ ".html"
#user-Agent头
user_agent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT6.1; Trident/5.0"
headers = {"User-Agent":user_agent}
req = urllib2.Request(url, headers = headers)
response = urllib2.urlopen(req)
print html
上述loadPage方法的实现逻辑应当较为熟悉,需注意在Python类中定义成员方法时,必须额外添加self参数。
第二步:编写main函数以测试loadPage方法
if __name__ == "__main__":
"""
=====================
内涵段子小爬虫
=====================
"""
print("请按下回车开始")
raw_input()
#定义一个Spider对象
mySpider = Spider()
mySpider.loadPage(1)
若程序运行正常,控制台将打印内涵段子第一页的完整HTML代码。但需注意,HTML中的中文部分可能显示为乱码。
因此,我们需要对获取的网页源代码进行简单处理:
def loadPage(self, page):
"""
@bridf 定义一个url请求网页的方法
@param page 需要请求的第几页
@returns 返回的页面html
"""
url = "http://www.neihan8.com/article/list_5_"+str(page)+".html"
#user-agent头
user-agent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT6.1; Trident/5.0"
headers = {"User-Agent":user-agent}
req = urllib2.Request(url, headers = headers)
response = urllib2.urlopen(req)
html = response.read()
gbk_html = html.decode("gbk").encode("utf-8")
return gbk_html
注意:不同网站对中文的编码方式各异,因此html.decode("gbk")的写法并非通用方案,需根据具体网站的编码格式进行调整。
第二步:利用正则表达式筛选数据
第二步:筛选数据
此时我们已获取整个页面的数据,但其中包含大量无关信息。下一步需利用上一节介绍的正则表达式对数据进行筛选。
首先,
import re
接着,我们在已解码的gbk_html字符串中进行正则匹配。
我们需要制定一个匹配规则。
打开内涵段子网页,右键点击“查看源代码”,会发现每个段子的内容均包裹在<div>标签中,且每个div标签均包含属性class="f18 mb20"。
基于正则表达式,我们可以推导出如下匹配公式:
<div.*?class="f18 mb20">(.*?)</div>
该表达式的实际作用是匹配所有class="f18 mb20"的div标签内部的内容(具体原理可参考前文介绍)。
将此正则表达式应用到代码中,得到以下实现:
def loadPage(self, page):
"""
@brief 定义一个url请求网页的办法
@param page 需要请求的第几页
@returns 返回的页面html
"""
url = "http://www.neihan8.com/article/list_5_" +str(page) + ".html"
#User-Agent头
user-agent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT6.1; Trident/5.0"
headers = {"User-Agent":user-agent}
req = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(req)
html = response.read()
gbk_html = html.decode("gbk").encode("utf-8")
#找到所有的段子内容<div class="f18 mb20"></div>
#re.S 如果没有re.S,则是只匹配一行有没有符合规则的字符串,如果没有则匹配下一行重新匹配
#如果加上re.S,则是将所有的字符串按一个整体进行匹配
pattern = re.compile(r'<div.*?class="f18 mb20">(.*?)</div>', re.S)
item_list = pattern.findall(gbk_html)
return item_list
def printOnePage(self, item_list, page):
"""
@brief 处理得到的段子列表
@param item_list 得到的段子列表
@param page处理第几页
"""
print("*********第%d页,爬取完毕...******"%page)
for item in item_list:
print("===============")
print ite
此处需注意re.S是正则表达式匹配时的一个关键参数。
- 若不使用re.S,则仅匹配当前行是否符合规则,若无匹配则换行继续尝试。
- 若添加re.S参数,则将整个字符串视为一个整体进行匹配,findall方法会将所有匹配结果封装到一个列表中返回。
- 若编写一个遍历item_list的方法printOnePage(),再次执行程序,
python duanzi_spider.py
第一页的所有段子内容(不含其他冗余信息)将被完整打印出来。
- 观察输出结果,会发现段子中包含许多<p>和</p>标签,这会影响文本的可读性。这些是HTML中的段落标签。
- 在浏览器中浏览时不易察觉,但若按纯文本打印则会显示<p>标签。因此,我们需要在输出前去除这些标签。
- 可以对printOnePage()方法进行如下简单修改:
def printOnePage(self, item_list, page):
"""
@brief 处理得到的段子列表
@param item_list 得到的段子列表
@param page 处理第几页
"""
print("******第%d页,爬取完毕*****"%page)
for item in item_list:
print("============")
item = item.replace("<p>", "").replace("</p>", "").replace("<br />", "")
print item
第三步:数据持久化保存
第三步:保存数据
我们可以将所有段子存储到文件中。例如,不直接打印每个item,而是将其写入名为duanzi.txt的文件中。
def writeToFile(self, text):
"""
@brief 将数据追加写进文件中
@param text 文件内容
"""
myFile = open("./duanzi.txt", "a") #a追加形式打开文件
myFile.write(text)
myFile.write("-------------------------")
myFile.close()
将原有的print语句替换为writeToFile()方法,当前页面的所有段子即可保存至本地的duanzi.txt文件中。
def printOnePage(self, item_list, page):
"""
@brief 处理得到的段子列表
@param item_list 得到的段子列表
@param page 处理第几页
"""
print("***第%d页,爬取完毕****"%page)
for item in item_list:
item = item.replace("<p>", "").replace("</p>", "").replace("<br />". "")
self.writeToFile(item)
第四步:遍历与显示数据
第四步:显示与遍历数据
接下来,通过参数传递使page变量递增,从而遍历内涵段子网站的所有页面内容。
只需在外层添加适当的逻辑处理即可实现。
def doWork(self):
"""
让爬虫开始工作
"""
while self.enable:
try:
item_list = self.loadPage(self.page)
except urllib2.URLError, e:
print e.reason
continue
#将得到的段子item_list处理
self.printOnePage(item_list, self.page)
self.page += 1
print "按回车继续...."
print "输入quit退出"
command = raw_input()
if(command == "quit"):
self.enable = False
break
以上即为本文的全部内容,希望对您的学习有所帮助,也欢迎大家继续支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









