我正在尝试解析 HTML 页面小狗。这是一个命令行 HTML 解析器,它接受通用 HTML 选择器。我知道我可以使用已经安装在我的机器上的 Python,但我想学习如何使用 pup 来练习命令行。
我想要抓取的网站是 https://ucr.fbi.gov/crime-in-the-us/2018/crime-in-the-us-2018/topic-pages/tables/table-1
我创建了一个 html 文件:
curl https://ucr.fbi.gov/crime-in-the-u.s/2018/crime-in-the-u.s.-2018/topic-pages/tables/table-1 > fbi2018.html
如何提取一列数据,例如“人口”?
这是我最初写的命令:
cat fbi2018.html | grep -A1 'cell31 ' | grep -v 'cell31 ' | sed 's/text-align: right;//' | sed 's/<[/]td>//' | sed 's/--//' | sed '/^[[:space:]]*$/d' | sort -nk1,1
它确实有效,但这是一种丑陋、hacky 的方法,这就是我想使用 pup 的原因。我注意到“人口”列中我需要的所有值都在标签headers="cell 31 .."
内的某个位置<td>
。例如:
<td id="cell211" class="odd group1 valignmentbottom numbercell" rowspan="1" colspan="1" headers="cell31 cell210">
323,405,935</td>
我想提取其标签中具有此特定标头的所有值<td>
,在这个特定示例中,将是323,405,935
然而,pup 中的多个选择器似乎不起作用。到目前为止,我可以选择所有 td 元素:
cat fbi2018.html | pup 'td'
但我不知道如何选择包含特定查询的标头。
编辑: 输出应该是:
272,690,813
281,421,906
285,317,559
287,973,924
290,788,976
293,656,842
296,507,061
299,398,484
301,621,157
304,059,724
307,006,550
309,330,219
311,587,816
313,873,685
316,497,531
318,907,401
320,896,618
323,405,935
325,147,121
327,167,434
答案1
总长DR
如果您想要该表的“人口”下的整列,请使用此选项:
... | pup 'div#table-data-container:nth-of-type(3) td.group1 text{}'
基本用法
pup
确实支持多个选择器。例如,如果您想抓取wanted text!!
以下内容:
$ cat file.html
<div>
<table>
<tr class='class-a'>
<td id='aaa'> some text </td>
<td id='bbb'> some other text. </td>
</tr>
<tr class='class-b'>
<td id='aaa'> wanted text!! </td>
<td id='bbb'> some other text. </td>
</tr>
</table>
</div>
$ cat file.html | pup 'div table tr.class-b td#aaa'
<td id="aaa">
wanted text!!
</td>
然后添加text{}
以仅获取文本:
$ cat file.html | pup 'div table tr.class-b td#aaa text{}'
wanted text!!
所以在你的情况下应该是:
$ cat fbi2018.html | pup 'td#cell211 text{}'
323,405,935
或者更好的是,您不必下载该页面,只需通过管道curl
即可pup
url="https://ucr.fbi.gov/crime-in-the-u.s/2018/crime-in-the-u.s.-2018/topic-pages/tables/table-1"
curl -s "$url" | pup 'td#cell211 text{}'
解释
如果您想要整个列中的值,那么您应该知道要抓取的元素的特征。
在本例中,来自给定链接的“人口”列。在页面上,有 2 个表包含在<div id='table-data-container'>...
如果您使用... | pup 'div#table-data-container'
,它也会从第二个表中获取数据。你不想要这样。
如何pup
知道您想要第一张桌子?嗯,还有另一个提示。正如你所看到的,s 很少<div>
。你的桌子在第三格。所以你可以使用CSS 的伪类, 在这种情况下div#table-data-container:nth-of-type(3)
然后,该列具有唯一选择器,如下所示td.group1
将它们全部组合起来,然后通过管道将其删除以grep -v -e '^$'
消除空格。
... | pup 'div#table-data-container:nth-of-type(3) td.group1 text{}' | grep -v -e '^$'
你会得到你想要的:
272,690,813
281,421,906
285,317,559
...
327,167,434