HACK#60 การค้นหาแบบกำหนดช่วงวันที่ (date-range searching) ด้วย Client-Side Application

วิธีการค้นหาข้อมูลที่ Google เพิ่งได้จัดทำอินเด็กซ์ข้อมูลนั้นเสร็จไป โดยจำกัดเฉพาะส่วนของเมื่อวานนี้เท่านั้น

GooFresh ใน Hack #42 เป็นเว็บฟอร์มแบบง่ายๆที่เขียนขึ้นด้วย CGI Script สำหรับการสร้างคำสั่งค้นหาแบบกำหนดช่วงวันที่ (date-range query) ซึ่งการใช้ Web-Based Interface นั้นค่อนข้างดีเมื่อคุณต้องการผลลัพธ์แค่เพียงหนึ่งหรือสองรายการในแต่ละ ครั้ง แต่คุณจะทำอย่างไรถ้าต้องค้นหาสิ่งที่ต้องการหลายๆครั้งหรือเป็นประจำ คำตอบก็คงเป็นการเซฟลงเครื่องคอมพิวเตอร์ของคุณ เพื่อนำมาวิเคราะห์เปรียบเทียบในภายหลัง
แต่มีวิธีที่ดีกว่าก็คือการใช้ Client-Side Application ที่เขียนด้วย Perl Script ซึ่งคุณสามารถรันจากเครื่องของคุณเองได้ โดยแอพพลิเคชันดังกล่าวจะส่งคำสั่งค้นหาที่คุณระบุ (specified query) ไปยัง Google โดยผ่าน Google Web API โดยขอให้จำกัดผลลัพธ์ของการค้นหาให้มีเพียงผลลัพธ์ที่เพิ่งถูกอินเด็กซ์ เมื่อวันวานเท่านั้น จากนั้นผลลัพธ์ที่ได้จากการค้นหา (search result) ในแต่ละครั้งจะถูกบันทึกเก็บไว้ โดยการนำผลลัพธ์ที่ได้เข้าไปต่อท้ายไฟล์ comma-delimited ที่กำหนดเอาไว้เท่านั้น ซึ่งผลที่ได้ก็สามารถ Import มายัง Excel หรือโปรแกรมด้านฐานข้อมูล (database application) อื่นใดก็ได้


Tip : การแฮ็กในหัวข้อนี้จำเป็นต้องมีโมดูล Time::JulianDay (http://search.cpan.org/author/MUIR/) ของ Perl ติดตั้งร่วมด้วย และสคริปต์จะไม่ทำงานเลย หากไม่ได้ติดตั้งโมดูลดังกล่าว

การค้นหา
ขั้น แรกคุณต้องเตรียมคีย์เวิร์ดที่เป็นคำถามเอาไว้สัก 2-3 คำถาม เพื่อทดลองใช้กับสคริปต์ จากนั้นลองใช้คำเหล่านี้ค้นหาใน Google ตามปกติก่อน เพื่อดูผลลัพธ์ที่ได้ให้แน่ใจว่าเป็นเรื่องที่เกี่ยวกับสิ่งคุณสนใจและต้อง การค้นหาจริงๆ ซึ่งคำถามดังกล่าวนี้อาจจะเป็นอะไรก็ได้ที่คุณต้องการจะติดตามเป็นระยะเวลา ยาวนานพอสมควร หรือคุณอาจใช้วิธีนี้ลองค้นหาข้อความบางอย่างอย่าง เช่น ถ้อยคำหรือวลีในบทความบางบท ซึ่งคุณคิดว่าไม่น่าจะ เหมือนกับข้อความในบทความอื่นๆ ซึ่งวิธีการนี้อาจจะทำให้คุณได้พบกับบทความที่มีการแอบคัดลอก หรือขโมยความคิดกันก็ได้
คุณ อาจจะใช้ซินแท็กซ์ที่คุณต้องการได้ ยกเว้นเพียงอย่างเดียวคือซินแท็กซ์ link: ถ้าหากคุณจำได้ถึงเนื้อหาในบทต้นๆที่บอกไปแล้วว่า link: ไม่สามารถใช้ร่วมกันซินแท็กซ์บางตัวอย่างเช่น daterange: ที่ใช้ใน Hack #60 ได้ แต่ถ้าหากคุณอยากทดลองใช้ร่วมกันดู (เช่น link:www.yahoo.com daterange:2452421-2452521 เป็นต้น) Google จะมองเหมือนกับว่าคำว่า link เป็นคำถาม ดังเช่นเดียวกับคุณต้องการค้นหาด้วยคำ 2 คำคือ link และ www.yahoo.com ซึ่งทำให้ผลลัพธ์ที่ได้ไม่ตรงกับความต้องการของคุณเลย
สำหรับการใช้งานสคริปต์ ให้ใส่คำถามที่เตรียมเอาไว้แล้ว โดยเรียงบรรทัดลงไปเรื่อยๆในลักษณะนี้
“digital archives”
intitle:”state library of”
intitle:directory intitle:resources
“now * * time for all good men * come * * aid * * party”
จากนั้นบันทึกเก็บไว้ในเท็กซ์ไฟล์ ซึ่งที่ที่ดีที่สุดในการเก็บไฟล์นี้ไว้ก็คือ ในไดเรกทอรีเดียวกับสคริปต์ของคุณนั่นเอง
โค้ดตัวอย่าง

#!/usr/local/bin/perl -w
# goonow.pl
# feeds queries specified in a text file to Google, querying
# for recent additions to the Google index. The script appends
# to CSV files, one per query, creating them if they don't exist.
# usage: perl goonow.pl [query_filename]

# My Google API developer's key
my $google_key='insert key here';

# Location of the GoogleSearch WSDL file
my $google_wdsl = "./GoogleSearch.wsdl";

use strict;

use SOAP::Lite;
use Time::JulianDay;

$ARGV[0] or die "usage: perl goonow.pl [query_filename]\n";

my $julian_date = int local_julian_day(time) - 2;

my $google_search = SOAP::Lite-&gtservice("file:$google_wdsl");

open QUERIES, $ARGV[0] or die "Couldn't read $ARGV[0]: $!";

while (my $query = &ltQUERIES&gt) {
chomp $query;
warn "Searching Google for $query\n"

$query .= " daterange:$julian_date-$julian_date";
(my $outfile = $query) =~ s/\W/_/g;
open (OUT, "&gt&gt $outfile.csv")
or die "Couldn't open $outfile.csv: $!\n";

my $results = $google_search -&gt
doGoogleSearch(
$google_key, $query, 0, 10, "false", "", "false",
"", "latin1", "latin1"
);
foreach (@{$results-&gt{'resultElements'}}) {
print OUT '"' . join('","', (
map {
s!\n!!g; # drop spurious newlines
s!&lt.+?&gt!!g; # drop all HTML tags
s!"!""!g; # double escape " marks
$_;
} @$_{'title','URL','snippet'}
) ) . "\"\n";
}
}
สังเกต สคริปต์ดู คุณจะเห็นว่า goonow จะระบุวันเป็นเมื่อวันก่อนนี้ แทนที่จะเป็นเมื่อวานนี้ (ดูบรรทัดที่เป็น my $julian_date = int local_julian_day(time) – 2;) เนื่องจาก Google รีอินเด็กซ์เว็บเพจบางหน้าบ่อยมาก ทำให้เว็บเพจหน้าดังกล่าวแสดงออกมาเต็มไปหมดในรายการผลลัพธ์ ดังนั้นถ้าหากคุณระบุเป็นวันวานจริงๆ (ใช้ -1 แทน -2) ผลลัพธ์ที่ได้จะมีเว็บเพจหน้าที่ถูกรีอินเด็กซ์บ่อยๆเต็มไปหมด (มีหลายเหตุผลที่ทำให้ต้องรีอินเด็กซ์เว็บเพจบางหน้าบ่อยๆหรือแทบทุกวัน ซึ่งจะได้อธิบายใ นโอกาสต่อไป) ดังนั้นถ้าหากคุณต้องการค้นหาข้อมูลของวันวานจริงๆ คุณควรจะบวกถอยหลังกลับไปหนึ่งวันเพื่อให้ได้ผลลัพธ์ที่ถูกต้องมากยิ่งขึ้น

Running the Hack
รันสคริปต์ที่ command line ดังนี้
$ perl goonow.pl query_filename

โดย ที่ query_filename จะเป็นชื่อของเท็กซ์ไฟล์ที่เก็บรายการคำถามเอาไว้ เพื่อส่งให้สคริปต์ทำงาน ซึ่งไฟล์นี้อาจจะอยู่ได้ทั้งที่โลคอลไดเรกทอรี (local directory) หรือที่อื่นก็ได้ แต่ถ้าเป็นที่อื่น อย่าลืมระบุพาธให้ถูกต้องด้วย (เช่น /mydocu~1/hacks/queries.txt เป็นต้น)
สำหรับผลลัพธ์ที่ได้จากค้นหาทั้งหมด จะถูกส่งไปยังไฟล์ CSV โดยไม่แสดงออกทางหน้าจอแต่อย่างใด
ผลลัพธ์
ลองดูตัวอย่างของไฟล์ CSV ที่แสดงผลลัพธ์ที่ได้จากการค้นหา


"State Library of Louisiana","http://www.state.lib.la.us/"," ...
Click
here if you have any questions or comments. Copyright &ltC2&gt&ltA9&gt
1998-2001 State Library of Louisiana Last modified: August 07,
2002. "
"STATE LIBRARY OF NEW SOUTH WALES, SYDNEY
AUSTRALIA","http://www.slnsw.gov.au/", " ... State Library of New
South
Wales Macquarie St, Sydney NSW Australia 2000 Phone: +61 2 9273
1414
Fax: +61 2 9273 1255. Your comments You could win a prize! ... "
"State Library of Victoria","http://www.slv.vic.gov.au/"," ...
clicking
on our logo. State Library of Victoria Logo with link to homepage
State
Library of Victoria. A world class cultural resource ... "
...
Hacking the Hack
สคริปต์ จะนำผลลัพธ์ที่ได้ในแต่ละครั้งไปต่อท้ายไฟล์ให้เองโดยอัตโนมัติ และถ้าหากคุณต้องการรีเซตไฟล์ CSV ที่ใช้เก็บผลลัพธ์ดังกล่าว ก็สามารถทำได้โดยเพียงการลบไฟล์นั้นออกไป แล้วสคริปต์จะสร้างไฟล์ขึ้นมาให้ใหม่อีกครั้งหนึ่ง
หรือ ถ้าหากคุณต้องการให้มีการสร้างไฟล์ CSV ขึ้นใหม่ทุกครั้ง สำหรับเก็บผลลัพธ์ในแต่ละครั้งที่ได้มา ก็เพียงแก้ไขสคริปต์เล็กน้อยดังนี้
...
(my $outfile = $query) =~ s/\W/_/g;
open (OUT, "> $outfile.csv")
or die "Couldn't open $outfile.csv: $!\n";
my $results = $google_search ->
doGoogleSearch(
$google_key, $query, 0, 10, "false", "", "false",
"", "latin1", "latin1"
);
...

สังเกต ว่าจะมีการแก้ไขสคริปต์เพียงเล็กน้อย โดยเพียงเอาเครื่องหมาย > ออก ให้เหลือเพียงตัวเดียว คือเปลี่ยนจาก OUT, “>> $outfile.csv” เป็น OUT, “> $outfile.csv” เท่านั้นเอง

โพสต์ยอดนิยมจากบล็อกนี้

ปัญหาและเฉลยธรรม นักธรรมชั้นโท สอบในสนามหลวง พ.ศ. ๒๕๔๓ วันพฤหัสบดี ที่ ๑๖ พฤศจิกายน พ.ศ. ๒๕๔๓

ปัญหาและเฉลยวินัยบัญญัติ นักธรรมชั้นเอก สอบในสนามหลวง พ.ศ. ๒๕๔๓ วันเสาร์ ที่ ๑๘ พฤศจิกายน พ.ศ. ๒๕๔๓

ปัญหาและเฉลยวิชาธรรม นักธรรมชั้นโท สอบในสนามหลวง วันเสาร์ ที่ ๑๙ พฤศจิกายน พ.ศ. ๒๕๔๘