بازیابی پستهای وبلاگ بلاگفا
تا مدتی میتوانیم پستهای وبلاگهای مسدود شده بلاگفا را به کمک اطلاعات موجود در کش گوگل دریافت کنیم. اینجا یک سری اسکریپت برای گرفتن اطلاعات یکی از وبلاگهایی که به این سرنوشت مغموم دچار شده، میآید.
خب. فرض بر این که blog.blogfa.com آدرس وبلاگ مرحوم باشد. در این صورت آرشیو وبلاگ (لیست ماهانه مطالب) از آدرس http://blog.blogfa.com/archive.aspx قابل دسترسی بود. بنابراین از آرشیو کش شده گوگل استفاده میکنم: http://webcache.googleusercontent.com/search?q=cache:blog.blogfa.com/archive.aspx
آدرس پستهای هر ماه واضح است. مثلاً blog.blogfa.com/8803.aspx یعنی مطالب خرداد ماه سال ۸۸. برای گرفتن صفحات ماههای اردیبهشت تا بهمن سال ۸۸ از این اسکریپت استفاده میکنم:
getindex.sh #!/bin/env sh mkdir index for month in `seq 8802 8811`; do wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1" \ "http://webcache.googleusercontent.com/search?q=cache:blog.blogfa.com/$month.aspx" -O index/$month.html done
فایلهایی که در پوشه index ساخته میشوند؛ شبیه فایل زیر هستند:
index/8805.html <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <base href="http://blog.blogfa.com/8805.aspx"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title> وبلاگ من</title> </head> <body> <div class="page" dir="rtl" > <div class="post"> <a name="61"></a> <div class="title"><a href="/post-61.aspx">پست مرحوم من</a></div> <div class="body"> <p> متن دلنشین من </p> <div class ="date">نوشته شده در دو شنبه بیست و پنجم مرداد 1388 ساعت 17:21 توسط من</div> </div> </div> </div> </body> </html>
البته خیلی خیلی بزرگتر و کثیفتر. این برای استخراح مطالب کافی نیست. چون احتمالاً فقط چند خط اول مطلب آمده و صفحه اصلی مطلب نیست.
صفحه اصلی مطلب blog.blogfa.com/post-61.aspx بوده که در
<div class="title">
آمده.
پس یک پارسر برای گرفتن این آدرسها از صفحات آرشیو لازم است تا بعد از طریق گوگل، اصل مطلب دریافت شود. صفحات xhtml نیستند که با کمک libxml به سادگی پارس شوند؛ در واقع طبق هیچ استاندارد html هم معتبر نیستند. خوشبختانه PHP Simple HTML DOM Parser میتواند صفحات خیلی درهم را هم پارس کند. پس میتوان با کمک یک اسکریپت PHP نشانی اصلی مطالب را فهمید:
getpostaddr.php <?php include 'simple_html_dom.php'; $dir = opendir( 'index' ); while( false !== ( $file = readdir( $dir ) ) ) { if( $file == '.' || $file == '..' ) continue; $html = file_get_html( "data/$file" ); foreach( $html->find( 'div[class=title] a') as $title_link ) echo substr( $title_link->getAttribute( 'href' ), 1 ).' '; } ?>
خروجی این اسکریپت چیزی است شبیه به:
post-138.aspx post-196.aspx post-250.aspx post-310.aspx post-371.aspx ...
باید نگه داشته شود:
posts=`php getpostaddr.php`
برای گرفتن مطالب از گوگل:
mkdir posts cd !$ for post in $posts; do [ -s $post ] || wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1" \ "http://webcache.googleusercontent.com/search?q=cache:blog.blogfa.com/$post" -O $post done find . -size 0 -exec rm '{}' \;
بعد از گرفتن حدود هر ۱۰۰ صفحه، گوگل نشانی IP گیرنده را مسدود میکند، پس حتماً از پراکسی استفاده کنید و http_proxy
قبلاً export شود.
فایلهای posts/post-*.aspx فایلهایی شبیه فایلهای صفحات فهرست (index) هستند که فقط یک پست دارند. به کمک یک پارسر دیگر عنوان، محتوی پست و تاریخ را از این فایلها میگیرم و به صورت xml چاپشان میکنم:
generatexml.php <?php include 'simple_html_dom.php'; $pdf = new IntlDateFormatter("en_US@calendar=persian", 0, 0, 'Asia/Tehran', IntlDateFormatter::TRADITIONAL, 'yyyy MM dd HH mm'); $gdf = new IntlDateFormatter("en_US", 0, 0, 'GMT',IntlDateFormatter::TRADITIONAL, 'EEE, dd MMM yyyy HH:mm:00 V'); $ri = "^نوشته شده در "; $by = 'توسط .*$'; $week_days = "(.*شنبه)|جمعه"; $month_literals = array( 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند' ); $number_literals = array( 'یکم', 'دوم', 'سوم', 'چهارم', 'پنجم', 'ششم', 'هفتم', 'هشتم', 'نهم', 'دهم', 'یازدهم', 'دوازدهم', 'سیزدهم', 'چهاردم', 'پانزدهم', 'شانزدهم', 'هفدهم', 'هجدهم', 'نوزدهم', 'بیستم', 'سی ام' ); function date_to_rfc822( $local_date ) { global $gdf, $pdf, $ri, $by, $week_days, $month_literals, $number_literals; $date = preg_replace( "/$by|$ri|$week_days/", "", $local_date); $gar = array(); preg_match( '/(\d{1,2}):(\d{1,2})/', $date, $gar ); $hour = $gar[1]; $minute = $gar[2]; $date = preg_replace( '/ساعت .*$/', '', $date ); preg_match( '/\d{4}$/', $date, $gar ); $year = $gar[0]; $months = implode( $month_literals, '|' ); preg_match( "/$months/", $date, $gar ); $month = array_search( $gar[0],$month_literals ) + 1; if ( array_search( $gar[0], $month_literals ) === False ) die( "month $gar[0]" ); $date = preg_replace( array("/$months/", '/\d{4}$/'), '', $date ); $days = implode( $number_literals, '|' ); preg_match( "/$days/", $date, $gar ); $day = array_search( $gar[0],$number_literals ) + 1; if ($day == 21) $day = 30; if( preg_match( '/بیست و .*/', $date ) ) $day += 20; else if ( preg_match('/سی و .*/', $date ) ) $day += 30; $timestamp = $pdf->parse( "$year $month $day $hour $minute" ); return $gdf->format($timestamp); } $dir = opendir('posts/'); echo "<rss>\n"; while( false !== ( $file = readdir( $dir ) ) ) { if( $file == '.' || $file == '..' ) continue; $html = file_get_html( "posts/$file" ); foreach ( $html->find('div[class=post]') as $post ) { echo "\t<item>\n"; foreach( $post->find(' div[class=date] ' ) as $date ) echo "\t\t<pubDate>".date_to_rfc822($date->plaintext)."</pubDate>\n"; foreach( $post->find('div[class=title] a') as $title) printf("\t\t<title>%s</title>\n", $title->plaintext); foreach( $post->find('div[class=body]') as $body) printf("\t\t<content:encoded>%s</content:encoded>\n", nl2br($body->plaintext) ); echo "\t\t</item>\n"; } } echo "</rss>\n"; ?>
کدهای تابع date_to_rfc822
و هر چیزی که بیرون while
قرار دارند، برای تبدیل:
نوشته شده در دو شنبه بیست و پنجم مرداد 1388 ساعت 17:23 توسط منبه صورت:
Mon, 16 Aug 2010 12:53:00 GMT
به کار میآید. تبدیل تاریخ شمسی به میلادی و حذف نام نویسنده و مانند اینها که در بلاگهای مختلف هم فرق میکنند و نیاز به کد متفاوت دارند.
php generatexml.php > posts.xml
posts.xml <rss> <item> <pubDate>Mon, 16 Aug 2010 12:53:00 GMT</pubDate> <title>پست مرحوم من</title> <content:encoded><p>متن دلنشین من</p></content:encoded> </item> <item> .......... </rss>
این فایل را میتوان به ورد پرس وارد کرد.