用jq怎么快找到p标签里头的数据库信息,简单又实用的方法分享
- 问答
- 2026-01-09 03:55:10
- 8
那天我在网上看到一个程序员提的问题,他说他手里有个巨大的JSON文件,是从某个网页抓下来的数据,里面乱七八糟什么都有,他需要从这里面把藏在层层嵌套里的、特别是HTML的<p>标签中的一些关键数据(比如用户评论、产品描述这类他称为“数据库信息”的文本)给提取出来,文件太大,用眼睛看会瞎,用一般的文本编辑器打开都卡死,下面有人回帖说:“用jq啊,神器!” 然后贴了条命令,看起来挺复杂,把提问的人都看懵了。
我当时就想,其实用jq干这个事儿,完全可以很直接,没必要一开始就上那些复杂的表达式,正好最近我也在处理类似的问题,就把我觉着最简单实用的几步分享一下,我的原则是,能一步到位就别分两步,能用简单语法就别写长脚本。
第一步:先看清敌人长啥样
这是最最要紧的一步,比什么都重要,你不能闭着眼睛乱摸,你的JSON文件结构是啥样的?那个你想要的、藏在p标签里的信息,它在第几层?你得先看一眼。
假设你的文件叫 data.json,打开终端,先来个最简单的:
jq '.' data.json
如果文件太大,输出会刷屏,那就用更偷懒的方法,只看第一个元素或者前几个元素,摸个样子出来:
jq '.[0]' data.json # 看第一个元素 # 或者 jq '.[:2]' data.json # 看前两个元素
你这么一看,发现数据结构大概是这样的:
{
"pages": [
{
"content": "<div><p>我们需要提取这里的文字</p><span>这个不需要</span></div>",
"title": "某个标题"
},
...
]
}
哦,你一下就明白了,你要的东西在 .pages[].content 这个字段里,而这个字段的值是一大段HTML字符串,你的目标就是这段HTML字符串里面的<p>标签里的文本。
第二步:把包含HTML的字段捞出来
现在你知道目标在 .pages[].content 里了,那就先把它单独拎出来看看:
jq '.pages[].content' data.json
这个命令会把所有pages数组里每一个元素的content字段值都打印出来,这时候你看到的就是一行行被引号包围的HTML字符串。
第三步(核心):对付HTML字符串,用contains和match
好了,关键来了,我们现在有一堆HTML字符串,怎么从里面找出包含<p>标签的那些,并且把里面的文本弄出来呢?这里有两个简单实用的方法。
方法A:快速过滤——我只关心有没有

你并不需要立刻看到p标签里具体的文字,你只是想快速知道,哪些条目它的content里包含了p标签,这时候,jq的contains函数就很好用。
jq '.pages[] | select(.content | contains("<p>"))' data.json
这个命令的意思是:遍历pages里的每个元素,然后筛选(select)出那些content字段的值里包含(contains)字符串"<p>"的元素,这样,输出结果就是完整的JSON对象,但只包含那些有p标签的条目,你可以在这个基础上再进一步处理。
方法B:直接抓取——我要文本内容
如果你想更近一步,直接把p标签里面的文本抠出来,那就得用正则表达式了。jq提供了match函数,虽然正则表达式听起来有点专业,但为了这个需求,我们只需要一个很简单的模式。
我们知道,一个简单的p标签长得像这样:<p>这里是文本</p>,我们想捕获的是这里是文本这部分,可以用这个命令:
jq '.pages[].content | match("<p>(.*?)</p>") | .captures[0].string' data.json
我来解释一下这个“咒语”:
.pages[].content:先把所有HTML字符串流出来。| match("<p>(.*?)</p>"):对每个字符串,用正则表达式<p>(.*?)</p>去匹配,括号表示一个非贪婪模式的捕获组,目的就是匹配<p>和</p>之间的所有内容。| .captures[0].string:match函数匹配成功后会返回一个对象,其中.captures数组里存放着捕获组的内容,我们取第一个捕获组([0]),然后它的.string属性就是我们想要的纯文本了。
这里有个大坑! 这是我从实际吃亏中总结的:HTML可能很乱,比如可能有多个p标签,或者p标签有大写的<P>,或者标签里有属性像<p class="style">,上面那个简单的正则可能就失灵了。
更健壮点的实用方法:

-
忽略大小写:在
match里加个"i"标志。jq '.pages[].content | match("<p>(.*?)</p>"; "i") | .captures[0].string' data.json -
处理有属性的标签:把正则改得更宽松点,匹配
<p开始,后面跟着任意字符直到>的。jq '.pages[].content | match("<p[^>]*>(.*?)</p>"; "i") | .captures[0].string' data.json这个
[^>]*意思是“匹配任意不是>的字符,重复0次或多次”,这样就能跳过标签内的所有属性。 -
处理多个p标签:如果你想提取所有的p标签内容,而不仅仅是第一个,就用
scan函数,它和match类似,但会返回所有匹配项。jq '.pages[].content | scan("<p[^>]*>(.*?)</p>"; "i") | .captures[0].string' data.json
第四步:输出整理
默认情况下,jq输出的字符串会带引号,如果你就是想得到纯文本,方便后续用其他命令(比如grep, awk)处理,可以加个-r选项,表示输出原始字符串。
jq -r '.pages[].content | scan("<p[^>]*>(.*?)</p>"; "i") | .captures[0].string' data.json
这样,终端里输出的就是一行行干净的文本了,直接可以重定向到文件里保存。
最后总结一下这个简单流程:
jq '.' data.json或jq '.[0]' data.json-> 看结构,找到目标字段路径。jq '你的路径' data.json-> 确认目标字段的值。- 选择你的武器:
- 只想过滤条目:用
select( .字段 | contains("p") )。 - 想直接提取文本:用
match或scan配合正则表达式,match("<p[^>]*>(.*?)</p>"; "i")。
- 只想过滤条目:用
- 优化输出:用
-r参数得到纯文本结果。
这个方法基本上能解决八成从JSON的HTML字段里抓p的需求了,如果HTML特别复杂,或者你需要解析整个DOM树,那可能就得考虑先用专门的HTML解析器处理后再转换成JSON,但对于快速的、命令行下的日志分析或者数据提取,这个jq组合技真的简单又实用。
本文由符海莹于2026-01-09发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/77211.html
