Python正则表达式实战:构建内涵段子爬虫

山海之间
山海之间
发布时间:2026-10-13 | 6人浏览过
原创

本文详解如何利用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

以上即为本文的全部内容,希望对您的学习有所帮助,也欢迎大家继续支持本站。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表