質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

PHP_正規表現又はDOMを使用して適切な抽出方法

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 924

SugiuraY

score 249

お世話になります。
現在、phpを使用しており正規表現またはDOMで以下のHTMLのようなデータから
一定の情報を正規表現又はDOMを使用することにより、抽出する事を試みております。
*正規表現により取得するデータは既に既にこちらのクライアント側にあるHTMLファイルであり、
取得先のサーバーへの負担等の問題は今回はご配慮頂かなくとも問題ございません。

【目的】
例えばですが、下記のHTMLをレンダリングした結果、以下のような構成になっております。
(A) aaaaa
(B) bbbbb,bbbbb
(C) ccccccc

これを例えば(A)について、以下のようなデータの抽出の方法を模索しています。

<p style="margin-left: 14px; text-align: justify; text-justify: inter-ideograph"> </p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">(A)</span>
</p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph; text-indent: 14px">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">aaaaa</span>
</p>

つまり(A)のブロックについて、次の(B)のブロックの直前まで、タグを含めてブロック毎することが趣旨になります。

【状況】
1.ここで(A)(B)(C)の前後のタグは特に法則ないです。
例えば、(A)の前にある以下のタグも必ず他のタグでもそうであるわけではありません。
<p style="margin-left: 14px; text-align: justify; text-justify: inter-ideograph"> </p> 
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph"> 
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">

2.今回は抜粋として(A)(B)(C)のブロックをお示ししましたが、実際には(A)(C)や(A)(D)(E)といったパターンもあり
これらのパターンを含めてブロックを取得する方法を一般化しようとしております。

3.全てに共通することは(A)(B)....(Z)について、これらがどのようなものであるかは把握されております。
例えば、(北海道)札幌市 (兵庫県)神戸市のようにイメージして頂ければと思います。

【質問】
・上記の通りタグやタグの属性法則がないため、DOMをうまく利用することができないのですが、
このようなケースでDOMで目的にあるようなブロックを取得することができるのでしょうか?
nodeValue((A)とかの内容)は分かっているの、そこからアプローチができるかとも思ったのですが、
試行錯誤しても目的を達成できませんでした。
・正規表現でやる場合に様々なケースに対応する必要があるため、難しいとは思うのですが(A)をキーにして
そのブロックを取得するのは可能でしょうか?また、そもそもこのようなケースの場合、DOMや正規表現ではない
方法が推奨される場合には、なにかアイデアがあればご助言を頂ければ幸いです。

<p style="margin-left: 14px; text-align: justify; text-justify: inter-ideograph"> </p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">(A)</span>
</p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph; text-indent: 14px">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">aaaaa</span>
</p>
<p style="text-align: justify; text-justify: inter-ideograph"> </p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">(B)</span>
</p>
<div style="margin-left: 24px">
<table style="table-layout: fixed; width: 624px" cellpadding="0" cellspacing="0">
<colgroup>
<col style="width: 156px"/>
<col style="width: 468px"/>
</colgroup>
<tbody>
<tr>
<td style="width: 155px; border-left: 1px solid transparent; border-right: 1px solid transparent"/>
<td style="border-left: 1px solid transparent; border-right: 1px solid transparent"/>
</tr>
<tr style="min-height: 1.33333337306976px">
<td style="border-left: 1px solid #000000; border-top: 1px solid #000000; border-right: 1px solid #000000; border-bottom: 1px solid #000000; vertical-align: top">
<p style="margin-left: 24px; margin-right: 4px; text-align: justify; text-justify: inter-ideograph; text-indent: -18px">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">bbbbb</span>
</p>
</td>
<td style="border-left: 1px solid #000000; border-top: 1px solid #000000; border-right: 1px solid #000000; border-bottom: 1px solid #000000; vertical-align: top">
<p style="margin-left: 24px; margin-right: 4px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">bbbb</span>
</p>
<p style="margin-left: 24px; margin-right: 4px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">bbbbbb</span>
</p>
</td>
</tr>
</tbody>
</table>
</div>
<p style="text-align: justify; text-justify: inter-ideograph"> </p>
<p style="margin-left: 36px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">(C)</span>
</p>
<p style="margin-left: 60.6666679382324px; text-align: justify; text-justify: inter-ideograph">
<span style="font-family: &apos;MS Mincho&apos;; font-size: 12px">ccccccc</span>
</p>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • think49

    2017/02/07 17:52 編集

    何を起点として抽出条件とするのかが不明瞭です。id,class属性が割り当てられているわけでもないようですが、`(A)`, `(B)` は抽出条件として使えるユニークな文字なのでしょうか。 あるいは、「style属性値が今後変更されない」という前提の元、style属性値を抽出条件にするのでしょうか。

    キャンセル

  • SugiuraY

    2017/02/07 18:24

    ご返信有難うございます。不明瞭な点お詫び申しあげます。>`(A)`, `(B)` は抽出条件として使えるユニークな文字なのでしょうか。 (回答)【状況】3.に記載のあるとおりユニークです。>あるいは、「style属性値が今後変更されない」という前提の元、style属性値を抽出条件にするのでしょうか。【状況】1.にあるとおり、ユニークではありません。ユニークなのはnodeValueとしての(A),(B)、、(Z)だけになります。またその範囲は既知であるということとなります。

    キャンセル

回答 2

+1

見た感じ
(classは省略)

<p> </p>
<p>
  <span>(A~C)</span>
</p>


で区切れそうなんだけどダメなの?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/07 18:43

    ご回答を頂き有難うございます。
    量が膨大のため、割愛をしておりますが、pタグとspanタグの関係は保証されておりません。唯一保証されているのは、(X)の中身に入りうるものを知っている、またそのブロックの範囲は次の(Y)のブロックがくるまでという点になります。ただし、最初に来るブロックと最後のブロックは前か後ろしか他のブロックに囲まれていないことになります。

    キャンセル

checkベストアンサー

0

前提の理解が間違っているかもしれませんが、「(北海道)札幌市」とかのイメージで考えると、以下のような形はいかがでしょうか。
(早く帰りたいのでソースがかなり雑ですが)

<?php
$dom = new DOMDocument('1.0', 'UTF-8');
#$dom->preserveWhiteSpace = false;
#$dom->formatOutput = true;
$dom->load("sample.html");

$xpath = new DOMXPath($dom);

$result = $xpath->query("//p/span");
echo "<ul>";
foreach($result as $element) {
    $node = $element->nodeValue;
    if(preg_match('/((.*))/i', $node, $matches)) {
        echo "</ul>".PHP_EOL;
        echo "<p>$node</p>".PHP_EOL;
        echo "<ul>".PHP_EOL;
    } else {
        echo "<li>$node</li>".PHP_EOL;
    }
}
echo "</ul>".PHP_EOL;


この結果は

<ul></ul>
<p>(A)</p>
<ul>
<li>aaaaa</li>
</ul>
<p>(B)</p>
<ul>
<li>bbbbb</li>
<li>bbbb</li>
<li>bbbbbb</li>
</ul>
<p>(C)</p>
<ul>
<li>ccccccc</li>
</ul>


となります。

Xpathで、<p>タグに囲まれた<span>タグを取得して、その中身を正規表現で取っています。
より正確にするためには、pタグのstyleやspanタグのstyle等を指定して

$result = $xpath->query("//p[@style='margin-left: 36px; text-align: justify; text-justify: inter-ideograph']/span");


などするとうまい事取れると思います。
(例示ソースを見ると、なぜかstyleが要素ごとにぶれているので、うまい事する必要はありそうですが)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る