影刀RPA 正则表达式实战:文本提取的高级武器

发布时间:2026/7/19 9:49:23
影刀RPA 正则表达式实战:文本提取的高级武器 影刀RPA 正则表达式实战文本提取的高级武器作者林焱什么情况用影刀内置了「提取文本」「匹配文本」等节点但遇到以下场景就抓瞎了从一段HTML里提取所有图片的src地址一段自由文本里提取出所有金额¥3,580.00、1580元、$299从100条日志中过滤出包含ERROR且后面跟着堆栈信息的行判断用户输入的身份证号格式是否正确这些不是简单的「找某个关键词」或「按分隔符切分」能搞定的——得用正则表达式。在影刀的Python节点里正则三行代码能顶二十个内置节点的效果。核心场景需要从非结构化文本中提取复杂模式的数据。怎么做第一步正则速查——30个最常用模式拼多多店群自动化报活动上架importre# 最常用的正则模式 PATTERNS{# 1. 手机号中国大陆phone:r1[3-9]\d{9},# 2. 身份证号18位id_card:r\d{17}[\dXx],# 3. 邮箱email:r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,},# 4. 网址URLurl:rhttps?://[^\s{}|\\^\[\]],# 5. IP地址ip:r\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3},# 6. 日期YYYY-MM-DDdate_iso:r\d{4}-\d{2}-\d{2},# 7. 日期YYYY年MM月DD日date_cn:r\d{4}年\d{1,2}月\d{1,2}日,# 8. 时间HH:MM:SStime:r\d{2}:\d{2}:\d{2},# 9. 金额带¥符号或元结尾amount:r[¥]\s*[\d,]\.?\d*|[\d,]\.?\d*\s*元,# 10. 百分比percent:r\d\.?\d*\s*%,# 11. 中文字符chinese:r[\u4e00-\u9fff],# 12. 英文字母大小写english:r[a-zA-Z],# 13. 数字digits:r\d,# 14. 小数decimal:r\d\.\d,# 15. 邮政编码zip_code:r\d{6},# 16. 车牌号plate:r[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤川青藏琼宁][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳],# 17. HTML标签html_tag:r[^],# 18. HTML img标签的srcimg_src:rimg[^]src[\]([^\])[\],# 19. Markdown链接 [text](url)md_link:r\[([^\]])\]\(([^)])\),# 20. 统一社会信用代码18位credit_code:r[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10},}# 快速测试deftest_pattern(pattern,text):matchesre.findall(pattern,text)returnmatchesprint(test_pattern(PATTERNS[phone],联系13812345678备用15987654321))# [13812345678, 15987654321]print(test_pattern(PATTERNS[amount],总价¥3,580.00优惠200元))# [¥3,580.00, 200元]print(test_pattern(PATTERNS[img_src],img classpic srchttps://img.com/1.jpg alt图))# [https://img.com/1.jpg]第二步Pattern写不出来的三个信号很多人卡在写Pattern上但有些场景根本不需要自己写信号1你在搜「XX正则表达式怎么写」→ 直接用上面的速查表或者让AI写。信号2同一个Pattern改了5次还没匹配上 → 用在线工具调试推荐 regex101.com可视化显示匹配结果。信号3Pattern越来越长、越来越像乱码 → 停下来可能你不需要正则用字符串的split()、find()、startswith()更简单更可读。第三步实战——从HTML中提取所有图片链接defextract_all_images_from_html(html):从HTML中提取所有图片URL# 匹配 img 标签的 src 属性img_urlsre.findall(rimg[^]src[\]([^\])[\],html)# 也匹配 background-image: url(...)bg_urlsre.findall(rbackground-image:\s*url\([\]?([^\)\s])[\]?\),html)# 去重 过滤掉base64内嵌图片all_urlsset()forurlinimg_urlsbg_urls:ifurlandnoturl.startswith(data:image):# 排除base64all_urls.add(url)returnlist(all_urls)第四步实战——日志文件解析defparse_nginx_log(log_line):解析Nginx访问日志patternr(\S) - - \[([^\]])\] (\S) (\S) \S (\d) (\d) ([^]*) ([^]*)matchre.match(pattern,log_line)ifmatch:return{ip:match.group(1),timestamp:match.group(2),method:match.group(3),path:match.group(4),status:int(match.group(5)),size:int(match.group(6)),referer:match.group(7),user_agent:match.group(8)}returnNone# 测试log192.168.1.1 - - [26/Jun/2024:14:30:00 0800] GET /api/products HTTP/1.1 200 1234 https://google.com Mozilla/5.0print(parse_nginx_log(log))第五步正则的性能优化——预编译非贪婪importtime# ❌ 差每次调用都编译正则defbad_extract(texts):results[]fortintexts:# 每次循环都重新编译一次foundre.findall(r\d{4}-\d{2}-\d{2},t)results.append(found)returnresults# ✅ 好预编译重复使用DATE_PATTERNre.compile(r\d{4}-\d{2}-\d{2})defgood_extract(texts):![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7b13d9c2049641af877aea41c9c712a1.png#pic_center)results[]fortintexts:foundDATE_PATTERN.findall(t)results.append(found)returnresults# 速度对比10000次调用text今天是2024-06-26昨天是2024-06-25texts[text]*10000# start time.time(); bad_extract(texts); print(f未预编译{time.time()-start:.3f}s)# start time.time(); good_extract(texts); print(f预编译{time.time()-start:.3f}s)# 差距约30-50%非贪婪匹配——最容易出bug的点htmldiv内容1/divdiv内容2/div# ❌ 贪婪匹配——匹配了所有内容直到最后一个/divgreedyre.findall(rdiv(.*)/div,html)print(greedy)# [内容1/divdiv内容2] —— 不是你想要的# ✅ 非贪婪匹配——遇到第一个/div就停lazyre.findall(rdiv(.*?)/div,html)print(lazy)# [内容1, 内容2] —— 正确加个?就是从贪婪变非贪婪这个小问号值千金。第六步正则与其他方法的组合拳别试图用一个正则解决所有问题。最实用的做法是组合defextract_structured_info(text): 从随意格式的文本中提取结构化信息 策略先用大范围匹配再用正则精细化提取 result{}# 1. 先分块——按「姓名」「电话」「地址」等关键词分割blocksre.split(r(姓名|电话|地址|邮箱|公司)[:],text)# 2. 逐块用对应的正则提取foriinrange(1,len(blocks),2):labelblocks[i].strip()valueblocks[i1].strip()ifi1len(blocks)elseif电话inlabel:phonere.search(r1[3-9]\d{9},value)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/04ccb46901ca489cbb772439e55ff2b5.png#pic_center)result[phone]phone.group()ifphoneelsevalueelif邮箱inlabel:emailre.search(r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,},value)result[email]email.group()ifemailelsevalueelif地址inlabel:result[address]value.strip()else:result[label]value.strip()returnresult# 测试text姓名张三 电话13812345678 地址北京市海淀区中关村大街1号 邮箱zhangsancompany.comprint(extract_structured_info(text))有什么坑坑1.默认不匹配换行符TEMU店群矩阵自动化运营核价报活动Python的re模块默认.不匹配换行符\n。text第一行\n第二行# ❌ 没匹配到print(re.findall(r第一行.*第二行,text))# []![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fe03b60501604c228a13ef3a8f77f1c2.png#pic_center)# ✅ 加上 re.DOTALL 标志print(re.findall(r第一行.*第二行,text,re.DOTALL))# [第一行\n第二行]坑2中文与\w的兼容性\w默认只匹配[a-zA-Z0-9_]不匹配中文。text用户名张三123# ❌ \w 不包含中文print(re.findall(r\w,text))# [123] —— 张三丢了# ✅ 加 re.A 或直接用字符类print(re.findall(r[\u4e00-\u9fff\w],text))# [用户名, 张三123]坑3正则回溯导致的性能灾难一个看似简单的正则遇到特定输入可能挂死。# 灾难性回溯的正则dangerousre.compile(r(a)b)# 遇到 aaaaaaaaaaaaaaaaaaaaac很多a但结尾不是b# 这个正则可能跑几秒钟甚至超时![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/901271adab3049a68475b50033a9a647.png#pic_center)texta*30c# dangerous.match(text) # 慎跑解决方法避免嵌套的量词(x)用(a)b就够了。坑4贪婪与非贪婪的直觉陷阱# 这段HTML里有多个spanhtmlspan classprice¥99/spanspan classdiscount-20/span# 直觉想到的Patternpricesre.findall(rspan[^]*(.*)/span,html)print(prices)# [¥99/spanspan classdiscount-20] —— 错了# 正确加 ?pricesre.findall(rspan[^]*(.*?)/span,html)print(prices)# [¥99, -20] —— 正确总结正则是RPA文本处理的高级武器但不要过度依赖。核心三板斧保存常用Pattern速查、用在线工具调试regex101.com、优先用split/find等字符串方法处理简单场景。记住那个小问号——.*?比.*安全一百倍。