いろいろなアプローチを試しては失敗をしたのですが、最終的にある程度の精度を出せる方法に行きついたのでここで紹介したいと思います。
【抽出アルゴリズム】
実際にはアルゴリズムというほど複雑な方法ではありませんが、結局は「人間の目で見てテキストが密集している部分をグループ化する」というアプローチが功を奏しました。
流れとしては以下になります。
- もしテキスト間のHTMLタグが5つ以下なら(つまり近くにあるなら)そのテキストは全てひとつのテキストとして結合させる。
- 結合したテキストをひとつひとつチェックし、テキストの長さが100以上あれば、それはコンテンツとして残す。
(HTML例)
<div>
<div>テキスト1</div>
<div>テキスト2</div>
<div>テキスト3</div>
</div>
<img src="***">
<img src="***">
<img src="***">
<div>
<div>テキスト4</div>
</div>
テキストが近いければ結合する
まず、「テキスト1」と「テキスト2」 の間には HTML が2つ(</div>と<div>)だけです。
つまり HTML 構造的にいうと距離は「2ステップ」の位置にあるため近いテキストということになります。
なので、この2つのテキストは結合します。
では、「テキスト3」と「テキスト4」はどうでしょう?
間にあるのは、
</div></div><img><img><img><div><div>
なので7ステップです。
デフォルトの基準は5ステップ以下なら結合することになっているのでこれは「遠いテキスト」ということで結合はしません。
これを全てのテキストで実行すると、ほぼ「見た目で近いテキストが集まったグループ」が作成できることになります。
テキストが長ければコンテンツとして抽出する
グループ別のテキストが作成できたので次にこのテキストがある程度以上長ければ残し、短ければ重要度が低いと判断し削除します。
このフィルターを通過したテキストがコンテンツ・テキストということになります。
ただし
この方法でもパーフェクトではありません。
また、紹介した方法をする前に <br> タグなどを一時的に退避させるなど HTML の加工が必要になりますのでご注意ください。
ソースコードのダウンロード
ということで、このコンテンツ抽出アルゴリズム(細々とした HTML の加工を含んでいます)を PHP クラス「Shellless」として公開しました。
Github でダウンロードか composer でインストールできるかと思いますのでもし興味がありましたらぜひアクセスしてみてください。
https://github.com/SUKOHI/Shellless
今回は以上です。(^o^)