Command-Line

用 pup 解析 HTML

  • July 16, 2021

我正在嘗試使用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

如何提取一列數據,例如“人口”?

這是我最初寫的命令:

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

TLDR

如果您想要該表的“人口”下的整個列,請使用此選項:

... | 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

或者更好的是,您不必下載頁面,只需管道curlpup

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'>...If you use ... | 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 '^$'

你會得到你想要的:

272,690,813
281,421,906
285,317,559
...
327,167,434

引用自:https://unix.stackexchange.com/questions/589798