web-dev-qa-db-ja.com

pupによる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

「人口」などのデータの列を抽出するにはどうすればよいですか?

これは私が最初に書いたコマンドです:

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 

それは実際には機能しますが、醜く、ハックな方法なので、子犬を使いたいのです。 「Population」列から必要なすべての値に、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になります。

しかし、子犬の複数のセレクターは機能しないようです。これまでのところ、すべてのtd要素を選択できます。

cat fbi2018.html | pup 'td'

しかし、特定のクエリを含むヘッダーを選択する方法がわかりません。

EDIT:出力は次のようになります。

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
rplee

基本的な使い方

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{}'
_

tldr;

そのテーブルの「母集団」の下に列全体が必要な場合は、これを使用します。

_... | pup 'div#table-data-container:nth-of-type(3) td.group1 text{}'
_

説明

列全体の値が必要な場合は、スクレイピングする要素の特性を知っている必要があります。

この場合、特定のリンクからの「人口」列。このページには、2つのテーブルが_<div id='table-data-container'>..._でラップされています。_... | pup 'div#table-data-container'_を使用すると、2番目のテーブルからデータも取得されます。あなたはそれを望まない。

tables

どのようにしてpupは最初のテーブルが必要かを知っていますか?さて、別のヒントがあります。ご覧のとおり、_<div>_ sはほとんどありません。そして、あなたのテーブルは3番目のdivにあります。したがって、 CSSの疑似クラス を使用できます。この場合はdiv#table-data-container:nth-of-type(3)

次に、列には_td.group1_のような一意のセレクターがあります。

selector

それらをすべて組み合わせてから、パイプを使用して_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
_
3
annahri

ここには2つの問題があります。
1)HTMLテーブルの値を解析します
2)希望する操作を実行します(最小、最大、電気ショック療法)

あなたはこれを一行で行うことができるとは思わない。 HTMLテーブルを.csvに変換してから、CSVを操作するのが好きです。そのためにAWKを使用できますが、代わりにPythonライブラリ、Pandasを使用します。それを回避できるのに、なぜbashと書くのですか?

私はbashを使用してHTMLテーブルを.csvに変換する方法を見つけました here

AWKを使用して列を平均化する例は here です。

0
bat