使用 pup 解析 HTML

rpl*_*lee 4 command-line html

我正在尝试使用pup解析 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
Run Code Online (Sandbox Code Playgroud)

如何提取一列数据,例如“人口”?

这是我最初写的命令:

curl https://ucr.fbi.gov/crime-in-the-u.s/2018/crime-in-the-u.s.-2018/topic-pages/tables/table-1 > fbi2018.html
Run Code Online (Sandbox Code Playgroud)

它实际上有效,但它是一种丑陋的、hacky 的方式,这就是为什么我想使用 pup。我注意到“人口”列中我需要的所有值都headers="cell 31 .."<td>标签内的某处。例如:

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 
Run Code Online (Sandbox Code Playgroud)

我想提取在其<td>标签中具有此特定标头的所有值,在此特定示例中,这将是323,405,935

然而,pup 中的多个选择器似乎不起作用。到目前为止,我可以选择所有 td 元素:

cat fbi2018.html | pup 'td'
Run Code Online (Sandbox Code Playgroud)

但我不知道如何选择包含特定查询的标题。

编辑: 输出应该是:

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
Run Code Online (Sandbox Code Playgroud)

ann*_*hri 6

TLDR

如果您想要该表的“人口”下的整列,请使用此选项:

... | pup 'div#table-data-container:nth-of-type(3) td.group1 text{}'
Run Code Online (Sandbox Code Playgroud)

基本用法

pup确实支持多个选择器。例如,如果您想抓取wanted text!!以下内容:

... | pup 'div#table-data-container:nth-of-type(3) td.group1 text{}'
Run Code Online (Sandbox Code Playgroud)

然后添加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>
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下它应该是:

$ cat file.html | pup 'div table tr.class-b td#aaa text{}'
 wanted text!!
Run Code Online (Sandbox Code Playgroud)

或者更好的是,您不必下载页面,只需通过管道curl发送到pup

$ cat fbi2018.html | pup 'td#cell211 text{}'

323,405,935
Run Code Online (Sandbox Code Playgroud)

解释

如果您想要来自整个列的值,那么您应该知道要抓取的元素的特征。

在这种情况下,来自给定链接的“人口”列。在页面上,有 2 个表包裹在 中<div id='table-data-container'>...如果使用 ... | pup 'div#table-data-container',它还会从第二个表中抓取数据。你不想那样。

桌子

你怎么pup知道你想要第一张桌子?嗯,还有一个提示。如您所见,<div>s很少。你的桌子在第三格。所以你可以使用CSS 的 psuedo-classes,在这种情况下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 '^$'
Run Code Online (Sandbox Code Playgroud)

你会得到你想要的:

272,690,813
281,421,906
285,317,559
...
327,167,434
Run Code Online (Sandbox Code Playgroud)