正则表达式在网页文件中文本识别匹配的应用

本文介绍了博主在学习Python编程时遇到的正则表达式难题,特别是如何从网页文档中提取经纬度数据。通过使用BeautifulSoup解析HTML并结合正则表达式,实现了对经纬度坐标的提取和解析,最终将字符串转换为浮点数列表,以便进一步处理。
摘要由CSDN通过智能技术生成

写在前面

2021年第一篇博客。
博主在编程学习过程中,如果说有哪个问题学起来感觉最费劲,那就一定是正则表达式了,其灵活的表达式还有各种限定、扩展让人无比头大,而博主工作中用的正则表达式很少,所以总是记不住。
趁着最近在看《Python核心编程》这本书,第一章就是正则表达式,又系统的学习了一遍,虽然还是一知半解,但稍微又理解了那么一点点。顺便拿个例子来练练手,记录一下思路,忘记时再过来翻翻。

  • 编程语言:Python3.7
  • 编译器:Spyder

业务需求

博主的目标是从一个网页文档中提取一堆经纬度数据,先给大家看看文档的核心内容:
在这里插入图片描述
图片中,我框出来的红色部分的经纬度坐标是我要提取出来的东西,但我并非要提取成一个一个的点,而是一组一组的点,比如第一组就是我框出来的两个点4个坐标值,这两个点要在一个子列表中,这个子列表应该还有两个子列表,也就是那两个点的坐标。绕不绕,我觉得挺绕,上图片比较直观,我最后想要获取的结果如下图:
在这里插入图片描述
这样够清楚了吧。
需求讲明白了就开始写代码吧。

代码实现

网页标签提取

前面说了,我这是一个网页文档,什么东西处理网页文档最高效,那当然是beautifulsoup,我要提取的核心内容在网页的第6个script标签中,所以我要写一段下面的代码:

from bs4 import BeautifulSoup
import re

filename = r'XXXX.html'
soup = BeautifulSoup(open(filename,encoding='utf-8'),features='html.parser')
soup = soup.find_all('script')
text = str(soup[5])

这是beautifulsoup的内容,我不细解释了,现在看看text的内容:
在这里插入图片描述
需要的内容在L.polyline(的下一行里面。

构建正则化表达式

分析一下字符串结构:
在这里插入图片描述
很明显,我要的东西是以.polyline(开头,换行之后的下一组经纬度坐标,所以标准的正则表达式应该是:
polyline(\n\s+([[.*?]])
下面我来解释一下这个正则表达式的意义:

  1. polyline这个可写可不写,因为我的文件里面可能还有其他点不是polyline的内容,所以我写上保证提取出来的点全是polyline里面的内容;
  2. \ (匹配左圆括号;
  3. \n匹配换行;
  4. \s+匹配一个或者多个空格,\s是匹配空格,+是匹配其次或多次;
  5. ([[.*?]])这一组比较关键,首先我有一组圆括号()并没有使用转义符\,那肯定不是匹配圆括号了,圆括号在正则表达式中可以实现下面任意一个(或者两个)功能,一是对正则表达式进行分组,二是匹配子组,这里就是匹配子组了;我写了两组[[及对应的]]用来表示我要匹配的字符串前后要有两个方括号,. *?用来匹配任意长度的字符串,其中?表示最短匹配,也就是说匹配到最短符合的那一个,如果不写?就成了贪婪匹配,匹配到最长的那个。

解释完了,那在Python里面到底该怎么写呢?看代码

res2 = re.findall('polyline\(\n\s+(\[\[.*?\]\])', text, re.DOTALL)

代码中我传入参数re.DOTALL,这又是个啥意思呢?
re.DOTALL表示.可以匹配换行符(\n),作用是能真正的匹配所有字符,默认情况下,正则表达式中的dot(.),表示所有除了换行的字符,加上re.DOTALL参数后,就是真正的所有字符了,包括换行符(\n)。
换句话说,如果我不传入re.DOTALL参数,.就匹配不到文档中的换行符。
还有个问题我得解释,为啥我这里使用的是最短匹配呢,也就是为啥我写的是. *?而非. *,正常情况下. *应该也是能匹配任意长度的字符串的,那正是因为我传入了re.DOTALL参数,导致我的正则表达式可以识别换行符了,那样如果用贪婪匹配的话,它就能找到最长符合的那个字符串,包括已经换行的内容,这显然不是我要的目的。
其实还可以这么写:

res2 = re.findall('polyline\(\n\s+(\[\[.*\]\])', text)

使用贪婪匹配,但是不传入re.DOTALL参数,那我匹配出来的永远只是那一行里面的内容,匹配结果一样。
好了,看看我匹配出来的是啥玩意儿吧:
在这里插入图片描述

字符串解析

对是对了,但是列表里面的内容全是字符串,而非有用的经纬度坐标,所以我还要对字符串进行处理,写一段下面的代码:

for i in range(len(res2)):
    res2[i] = res2[i].replace('[[', '').replace(']]', '').replace(' ','').split('],[')
    for j in range(len(res2[i])):
        res2[i][j] = res2[i][j].split(',')
        for k in range(len(res2[i][j])):
            res2[i][j][k] = float(res2[i][j][k])

这段是数据清洗的内容,不详细讲了。

完整代码

from bs4 import BeautifulSoup
import re

filename = r'C:\Users\HP\Desktop\在办工作\25-所级课题研究\典型道路事故\钱荣路.html'
soup = BeautifulSoup(open(filename,encoding='utf-8'),features='html.parser')
soup = soup.find_all('script')
text = str(soup[5])

# 第二种匹配方法
# 未转义的一组圆括号用来分组匹配,.*?用来匹配任意长度的字符串,其中?表示最短匹配,
# 也就是说匹配到最短符合的那一个,如果不写?就成了贪婪匹配,匹配到最长的那个,
# re.DOTALL表示.可以匹配换行符(\n),作用是能真正的匹配所有字符
res2 = re.findall('polyline\(\n\s+(\[\[.*?\]\])', text, re.DOTALL)
# 上面取出来的列表里的元素是字符串,还是需要转换才行
for i in range(len(res2)):
    res2[i] = res2[i].replace('[[', '').replace(']]', '').replace(' ','').split('],[')
    for j in range(len(res2[i])):
        res2[i][j] = res2[i][j].split(',')
        for k in range(len(res2[i][j])):
            res2[i][j][k] = float(res2[i][j][k])

注释里可以看到,这是我的第二种匹配方法,第一种写的,简直一塌糊涂,就不丢人现眼了。

写在后面

正则表达式是编程人员需要掌握的一个重点知识点,这篇博客是我在摸索很久后一直感觉不得要领,然后向读研时的同袍学习后总结的,学习路上需要有个领路人,虽然已经很久不见,但是依然是值得信赖的好基友。
努力学习,共勉。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栀椩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值