まとめアンテナを作る時に使ったテクニックです。

個人的な情報収集用に、まとめサイトのアンテナを作って自分で見ているのですが、取得を停止しているまとめの取得を再開しようと考えました。となると、過去記事の情報をなんとかして取らないといけないわけでして、記事一覧に埋め込まれてるrdf部分だけを取得できないか考えました(知恵袋で知恵を拝借しました)

xpathで取得しようと思ったけど、うまくいかないので、まずは力技で抜く

サンプルなんですけど、例としてhttp://workingnews.blog117.fc2.com/ このサイトから。

中身をみると、以下のような内容が含まれています

<!--<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description rdf:about="http://workingnews.blog117.fc2.com/blog-entry-12228.html" trackback:ping="http://workingnews.blog117.fc2.com/tb.php/12228-5fa1fc55" dc:title="年商10億以上の会社に勤めてるけどボーナス入ったから明細うpしとくわ" dc:identifier="http://workingnews.blog117.fc2.com/blog-entry-12228.html" dc:subject="その他・特殊業界" dc:description="元スレ:http://news4vip/1545222338/ 1 :以下、?ちゃんねるからVIPがお送りします:2018/12/19(水) 21:25:38.365 ID:i9IRZFVe0.net せめて平均くれよん &nbsp; &nbsp; &nbsp; 2 :以下、?ちゃんねるからVIPがお送りします:2018/12/19(水) 21:26:09.899 ID:9FxRyD8Bp.net 手渡し? &nbsp; 3 :以下、?ちゃんねるからVIPがお送りします:2018/12/19(水) 21:26:33.317 ID:FTxUFyRSM.net 手書きwww &nbsp; 4 :以下、?ちゃん..." dc:creator="waku_new" dc:date="2018-12-21T01:06:11+09:00" />
</rdf:RDF>
 -->

他のブログサイトではきっちり改行されていますが、あえて改行されていなかったこのサイトを例にしました。

ページの中に数カ所該当する部分がありますので、各箇所を切り取ってみて、配列に入れたいと思います。

strposを使って開始位置と終了位置を特定、その数値を以って切り取る

理屈的には、「<rdf:RDF」が始まる位置を特定して、次に「</rdf:RDF>」の最後の文字のところを特定して切り取る。「</rdf:RDF>」は10文字なので、strposで出てきた位置+10で終了位置を決める。

以下、コード

$html = @file_get_contents($target_url);

if ($html === false) { die('read abort'); } 
$rdf = [];

while (($start = strpos($html, '<rdf:RDF')) !== false) { 
$str = substr($html, $start); 
$end = strpos($str, '</rdf:RDF>') + 10; 
$rdf[] = substr($str, 0, $end); 
$html = substr($str, $end+1); 
}

最初に出てきたrdfのブロックを取得したら、取得終わったところまでをカットして、カットしたテキストに対して再度rdfを探すループを繰り返しています。※知恵袋で回答してもらった内容

rdfの配列には各記事のrdfが入っているので、今度はその中身に対して、それぞれ記事情報を1件ずつ取得していきます。

正規表現で各データを取得する

rdfを取得できたら、今度は各パラメータで欲しい部分を取得していきます。

以下、コード。

foreach($rdf as $r){
///title 
preg_match("/.*dc:title.*/",$r,$match); 
$title= trim(preg_replace('/.*dc:title="(.*?)".*/','$1',$match[0])); 

//url preg_match("/.*dc:identifier.*/",$r,$match); 
$url= trim(preg_replace('/.*dc:identifier="(.*?)".*/','$1',$match[0])); 

///description 
preg_match("/.*dc:description.*/",$r,$match); 
$description= strip_tags(trim(preg_replace('/.*dc:description="(.*?)".*/','$1',$match[0]))); 

///author 
preg_match("/.*dc:creator.*/",$r,$match); 
$user_nick= trim(preg_replace('/.*dc:creator="(.*?)".*/','$1',$match[0])); 

///date preg_match("/.*dc:date.*/",$r,$match); 
$date= trim(preg_replace('/.*dc:date="(.*?)".*/','$1',$match[0])); 

}
 

今回のデータでは、改行が入ってなかったデータだったので、まずは該当の名前空間のデータがあるかどうかをチェックしてから、正規表現で取り出すようにしました。無事に綺麗に取れました。

で、最後のページまでデータを取るためには、最初の取得ページのurlを次のページへ差し替えないといけません。上記処理が終わったら、以下内容を実行して、次のurlに差し替えます。※ただし、該当タグが入っていればですが。

///次ページがあるか確認 
$dom = new DOMDocument; 
@$dom->loadHTML(mb_convert_encoding(file_get_contents($target_url), 'HTML-ENTITIES', 'UTF-8')); 
$xpath = new DOMXPath($dom); 

// metaタグに次ページの指定があれば、そこから取得する。
//今回のサイトでは、url=で指定があったため、getAttributeをurlにしてますが
//他のサイトではhrefがほとんどでした。
$tmp=$xpath->query('//link[@rel="next"]'); 
if(method_exists($tmp->item(0),'getAttribute')){ 
$target_url=$tmp->item(0)->getAttribute("url");
 }
else{ 
//最後のページの時の処理 
}

こんな感じで、ひとまずメモがてらでした。

コメント