pagetaka

写真、PC、ネット、岡山、旅の話題をお届けします

PHP:正規表現で「href」のリンクURLが抽出できない?

PHPでDOMとかWEBスクレイピングし、RSS未設置のサイト更新情報を得たいと妄想中の爺です。

今朝は、HTML「a」タグ要素「href」に続くURL(リンク先)を抜き出せないというトラブルに見舞われました…。

経過と状況

  • 昨夜は、Aサイトでpreg_match(正規表現)はできた
  • 今朝は、Bサイトで、一部できない
  • 表示されるのは、抽出結果を格納する配列が一部でできあがってないのだ…。

昨夜使ったPHPスクリプト、例(部分)[追記:↓不十分なマッチングになるようです]

include_once('C:/xampp/php/simple_html_dom.php');
$getHTML = file_get_html("http://x.jp/"); //←URLは例示
foreach($getHTML->find('a') as $elements){
	preg_match("|<a href=\"(.*?)\".*?>(.*?)</a>|mis",$elements,$parts);
	echo $parts[1]."<br />";
}

これは、aタグを拾って、その情報を配列$parts[]に入れなさい。そのうち、URLだけ(=$parts[1])表示しなさい、というようなことです。

これが、Bサイトでは、一部上手くいかない…はて?
で、Bサイトの該当部分をOKのところとNGな部分に分け、観察したです。

「href="URL"」にある2個の「"」有無 そのほか

[追記:2015-7-7]正規表現、不十分な条件設定であったことがわかりました。以下を書き直しました。

HTML「a」タグはエラーを含め、色々に表現される可能性があります。

<a rel"uuu" href="http://x.jp" target="xxx">x-site</a>
↑を正規表現 |href=\"{0,}(.*?)\"{0,}\.*>|misで取り出すと配列[1]には
http://x.jp" target="xxx が

<a rel"uuu" href=http://x.jp target="xxx">x-site</a>
↑だと正規表現で取り出すと配列[1]は
http://x.jp target="xxx

この結果、爺の正規表現のあやふやな知識では、一回で必要なURLを取得できそうもないことがわかりました。

とりあえずの正規表現とその結果

<?php
$texts=array();
	$texts[0]='<a rel\"uuu\" href="http://x.jp">x-site</a>';
	$texts[1]='<a rel\"uuu\" href="http://x.jp" >x-site</a>';
	$texts[2]='<a rel\"uuu\" href=http://x.jp">x-site</a>';
	$texts[3]='<a rel\"uuu\" href=http://x.jp" >x-site</a>';
	$texts[4]='<a rel\"uuu\" href=http://x.jp>x-site</a>';
	$texts[5]='<a rel\"uuu\" href=http://x.jp >x-site</a>';
	$texts[6]='<a rel\"uuu\" href="http://x.jp" target="ddd">x-site</a>';
	$texts[7]='<a rel\"uuu\" href=http://x.jp target="ddd">x-site</a>';
$n =0;
foreach($texts as $text){
	preg_match("|href=\"{0,}(.*?)\"{0,}\.*>|mis",$text,$parts);
	echo $n."-- ".$parts[1]."<br />";
	$n++;
}
?>

上のスクリプトのうち「|href=\"{0,}(.*?)\"{0,}\.*>」が正規表現のキモ部分です。
いろんなパターンで実行した結果の画像は下の通りです。
f:id:PageTAKA:20150707215915j:plain
そして余分な空白を確認してみると、「」が文字などから離れてあるのが空白の存在を示しているということになります。
f:id:PageTAKA:20150707220124j:plain

文字列を左から読んでいって、目印を見つける

http://x.jp" target="xxxhttp://x.jp target="xxx の二つのタイプのURL関連文字が配列[1]にあることになります。target属性がなどがないこともありますが、左から見ていくと「 」(半角空白≒おそらく…)または「" 」(ダブルクォーテーション+半角空白)の並びが出現するなど修正が必要な状態、または、URL後に文字や空白が無いOK状態のいずれかということがわかります。

  1. 左から文字列全体をチェックし半角空白があるかないかで、まず判断する。半角空白が無い場合は、配列[1]がそのままURLとなり完了
  2. それ以外の場合、文字列を左からチェックし、半角の空白を見つけたら、それを目印に文字列を分け、左半分を変数$leftに格納する
  3. 変数$leftの右部分に「"」があれば削除する。その結果得られた文字列は取得したいURLとなる、と妄想したです。

あ~つかれた~。上手く本日中には着地できなかった。シク・シク。明日以降の宿題(←忘れるためにある…はて・)なのでありました~。
gggggg~