หน้าเว็บ

วันจันทร์ที่ 4 มกราคม พ.ศ. 2553

Automate website ด้วย Mechanize ...แหล่มมากๆ

ลายวันก่อน ได้รับมอบหมายงานๆนึงจากหัวหน้า เป็นงานรูทีนให้เราตามอัพเดต status ของชิ้นงานใน line ผลิต ซึ่งงานนี้ต้องนั่งอัพเดตผ่านโลคอลเวปไซต์ที่เปิดใช้อยู่ใน intranet ของบริษัท งานหนึ่งชิ้นต้องคลิกอัพเดตกัน 4 links อ่า ดูไม่น่าสนุกเหมือนนั่งเล่น pantip ซะแล้ว
งานนี้เคยบอกไปทีแล้วว่า มันไม่ควรจะใช้คนมานั่ง track นะเพราะมันเสียเวลาและไม่ practical อย่างยิ่ง สำหรับงาน mass ยิ่งตัว product ต้องการ traciability สูงๆแล้วยิ่งไม่ควร
แต่ก็นะ ท่านก็ยังอยากให้นั่ง track
โอเค
นั่งทำใจอยู่พักนึงก่อนจะพลิกมุมคิด ให้มองโลกในแง่บวก เลยหาวิธีที่จะทำยังไงให้ไม่ต้องมานั่งท่องเวปคอยอัพเดต status ของชิ้นงาน สุดท้ายก็เจอแนวทางดีๆเข้าจนได้ นั่นก็คือการใช้ไลบรารี Mechanize มา automate เวปไซต์โดยเราทำหน้าที่เขียนโค้ดสั่งให้มันคลิก link, กรอก form, กด submit form บนหน้าเวปไซต์ให้เราโดยอัตโนมัติ ฮ่าๆ ทีนี้เราก็ไม่ต้องมานั่งแช่อยู่หน้าเวปบริษัทแล้ว เอาเวลาไป chat กะ(เพื่อน)สาวแล้วปล่อย Mechanize ทำงานให้เราดีกว่า หุหุหุ

Mechanize คืออะไร
Mechanize คือไลบรารี่ของ ruby ซึ่งเราสามารถนำมันมาใช้ควบคุมหน้า website ให้เราโดยอัตโนมัติ ไม่ว่าจะเป็นการสั่งให้ click ไปยัง link ที่เราต้องการ, กรอกข้อมูลลงใน form แล้วกด submit รวมถึงความสามารถในดึงข้อมูลที่อยู่ในหน้า HTML ออกมาแสดงผลหรือที่รู้จักกันในนามของการ scrub ข้อมูลก็ทำได้ด้วย

นอกจากไลบรารี่ Mechanize แล้วยังมีไลบรารี่อีกหลายตัวที่มีความสามารถในการควบคุมสั่งการหรือดึงข้อมูลออกมาจาก website ได้เหมือนกันเช่น open-uri(ตัวนี้ป็น standard library ของ Ruby เลย ไลรารี่ตัวอื่นๆส่วนใหญ่ก็นำคุณสมบัติจากไลบรารี่ตัวนี้แหละมาใช้งาน), hpricot, nokogiri, scrubyt เป็นต้น
ตอนนี้เราอย่าเพิ่งสนใจเรื่องข้อดีข้อเด่นของ library แต่ละตัว ไปดูก่อนดีกว่าครับว่า Mechanize ที่จะพูดถึงในวันนี้มันทำอะไรได้บ้าง

น่าสนนะ แล้วต้องเตรียมอะไรบ้างถ้าอยากใช้ Mechanize
Mechanize เป็นไลบรารีของ Ruby อันนี้ผมสมมติเราติดตั้ง Ruby กันเรียบร้อยแล้วนะ ถ้าใครยังไม่ได้ติดตั้ง Ruby ก็ลองกลับไปอ่านตอนเก่าได้ที่นี่นะครับ
จากนั้นเราก็ไปโหลด library มาใช้ซึ่ง Mechanize นั้นเป็นมี file ที่เป็น gems library เรียบร้อยแล้ว เราจึงสามารถดาวโหลดมาใช้ผ่านทาง RubyGem ได้เลยโดยพิมพ์คำสั่งต่อไปนี้ลงใน command line(อย่าลืมต่อ net ก่อนนะ)
C:\gem install mechanize

เครื่องมืออีกตัวที่จำเป็นก็คือโปรแกรมแสดงข้อมูล node ต่างๆของหน้าเวป HTML ถ้าใครใช้ IE ก็ให้หาโปรแกรมจำพวก DOM inspector มาใช้ ส่วนใครที่ใช้ Firefox นั้นสบายหน่อยเพราะมี DOM inspector ติดมากับ Firefox อยู่แล้ว แต่ผมขอแนะนำให้ติดตั้ง Add-on ที่ชื่อ FireBug เพิ่มเข้าไปดีกว่าครับ เพราะเจ้า Firebug ตัวนี้ใช้หาโหนดของ component ที่เราสนใจได้ง่ายกว่ามาก


หน้าตาของ Firefox กับ plug-in ที่ชื่อ Firebug ครับ

Mechanize ใช้ยังไง
ความสามารถหลักๆของ Mechanize ก็คือการ automate หน้า website ดังนั้นผมจึงขอยกตัวอย่างของการนำ Mechanize ไปใช้ในกรณีต่างๆกันไป ดังนี้ครับ

แสดงผลของการค้นหาข้อมูลในเวป google
อันนี้เป็นตัวอย่างที่ง่ายที่สุดที่จะทำให้เราเห็นภาพทันที โดยเราจะเข้าไปยังหน้าแรกของ google.com แล้วใส่คีย์เวิร์ดลงไปใน input box แล้วกดปุ่มค้นหา อ่า แน่นอนครับว่าเราจะเขียนโค้ดโดยใช้ Mechanize ในการทำกระบวนการที่ว่ามาทั้งหนดนี้

อันดับแรกเลย เราต้อง require ไลบรารี่ Mechanize เข้ามาก่อนจากนั้นสร้างอ็อบเจกต์ agent จากคลาส WWW::Mechanize ซึ่งเจ้าอ็อบเจกต์ agent นี่แหละจะทำหน้าที่เป็นเสมือน web browser ให้กับโค้ดของเรา

test_mechanize.rb
require 'mechanize'

agent = require 'mechanize'
 
agent = WWW::Mechanize.new
main_page = agent.get('http://www.google.com/ncr')

main_page จากโค้ดในบรรทัดที่ 4 จะเก็บค่าของหน้าเว็บ www.google.com/ncr โดย main_page จะเป็นอ็อบเจกต์ของคลาส Page ซึ่งเราจะใช้มันเป็นตัวกลางในการติดต่อกับหน้าเว็บเพจจริงๆต่อไป
ให้สังเกตุว่า/ncr ที่ผมใส่ไว้หลัง www.google.com ก็เพื่อบังคับให้ google แสดงผลในหน้าที่เป็นภาษาอังกฤษเท่านั้น ดังนั้นเวลารันโค้ดคุณผู้อ่านกับผมจะได้ผลของการค้นหาที่ตรงกันไงครับ

เมื่อได้หน้าเวป google มาอยู่ในอ็อบเจกต์ main_page แล้วขั้นตอนต่อไปเราจะป้อน keyword ที่เราจะค้นหาลงไปใน input text field ของหน้าเว็บ แต่เราต้องรู้ก่อนว่าเจ้า input text field เนี่ยมันอยู่ส่วนไหนภายในอ็อบเจกต์ main_page และเราจะกำหนดค่ามันอย่างไร
เนื่องจาก input text field นั้นเป็นส่วนหนึ่งของ form ที่เราต้องกด submit(ค้นหา) ดังนั้นเราจึงต้องบอกโค้ดของเราด้วยว่าเราจะทำงานกับ form ตัวไหนใน หน้าเว็บนั้น
ซึ่งเราสามารถอ้างอิง form กับโค้ด Ruby ของเราได้จากชื่อของ form ที่ปรากฎอยู่ในโค้ด HTML โดยเราจะเรียกดูชื่อของ form จากโค้ด HTML ได้ผ่านทาง Firebug หรือโปรแกรม DOM inspector แต่ในที่นี้ผมขอใช้ Firebug นะครับ

ขอแทรกวิธีการใช้ Firebug เพื่อดูชื่อของ component ต่างๆสักนิดนึงนะครับ
เราแค่เปิดหน้า Firebug ขึ้นมาจากการ click ไอคอนรูปแมลงที่มุมขวาล่างของ Firefox
จากนั้นให้เรากดที่ปุ่ม สีเหลี่ยม ตามรูปด้านล่างนี้เพื่อเข้าสู่โหมดของ Firebug แล้วก็ click ไปยัง component โหนดที่เราต้องการรู้รายละเอียด มันก็จะ show โหนดของ component นั้นเป็นโค้ด HTML ขึ้นมา นอกจากนี้เรายังสามารถดูรายละเอียดอื่นๆโดยกดที่แท็ป DOM ได้อีกด้วย

[firebug_2.jpg]

จากตัวอย่างจะพบว่าชื่อของ input text field ของหน้า google ที่ปรากฎอยู่ในโค้ด HTML นั้นก็คือค่าที่อยู่ใน field name ที่อยู่ใน HTML tag นั้นเอง ซึ่งในที่นี้ค่าของ name จาก tag form จะมีค่าเป็น 'f' ในขณะที่ค่าของ name จาก tag input ที่อยู่ใน form จะมีค่าเป็น 'q'

เราจะนำค่าของ HTML tag ที่ได้มาเขียนโค้ดต่อไป ซึ่งคือขั้นตอนของการป้อนคีย์เวริ์ดที่เราต้องการให้ google ค้นหาแล้วกดปุ่ม "Google Search" โดยสมมติให้คีย์เวิร์ดในการค้นหาคือคำว่า "ruby"
โค้ดของเราจะมีหน้าตาประมาณนี้ครับ

auto_google.rb
require 'mechanize'
 
agent = WWW::Mechanize.new
main_page = agent.get('http://www.google.com/ncr')
 
main_form = main_page.form_with(:name => 'f')
main_form.q = "ruby"
 
search_result_page = agent.submit(main_form)
search_result_page.links.each do link
  if link.text =~ /ruby/ then puts link.text end 
end

ตัวแปร main_form ที่เราเห็นก็คือ อ็อบเจกต์ของคลาส Form ที่ได้มาจากเมธอด form_with ในบรรทัดที่ 6
ชื่อของ tag HTML ที่อยู่ใน form ในหน้าเว็บเพจนี้จะกลายไปเป็น attribute ให้กับอ็อบเจกต์ main_form ดังนั้นเราจึงสามารถกำหนดค่าที่ต้องการให้กับ attribute ของ form ได้ จากตัวอย่างในบรรทัดที่ 7 เป็นการกำหนดค่า "ruby" ให้กับ attribute 'q' ซึ่งเป็นชื่อของ input tag นั่นเอง

หลังจากกำหนดค่าให้กับ attribute ของ form เป็นที่เรียบร้อยแล้วก็ถึงเวลากดปุ่ม "Google Search" ซึ่งก็คือการใช้เมธอด submit จาก อ็อบเจกต์ agent โดยใส่อ็อบเจกต์ Form อย่าง main_form เข้าไปเป็นพารามิเตอร์ ผลที่ได้ก็คือ content ของหน้าเว็บเพจทั้งหน้าหลังจาก submit ซึ่งถูกเก็บอยู่ในตัวแปร search_result_page ในบรรทัดที่ 9

searcg_result_page นั่นเป็นอ็อบเจกต์ของคลาส Page ซึ่งมันมีเมธอด links ซึ่งทำหน้าที่ return อาเรย์ของอ็อบเจกต์ link ในหน้าเว็บเพจนั้นๆออกมา
โค้ดในบรรทัดที่ 10-12 จึงเป็นการแสดงค่าของ link ที่อยู่ในหน้า search_result_page โดยแสดงเฉพาะ link ที่มีคำว่า 'Ruby' เป็นส่วนหนึ่งของชื่อ link เท่านั้น

ผลลัพธ์ของการรันโค้ดดังกล่าวจะได้ดังนี้

Ruby Programming Language
Ruby in Twenty Minutes
About Ruby
Download Ruby
Ruby - The Inspirational Weight Loss Journey on the Style Network ...
Ruby (programming language) - Wikipedia, the free encyclopedia
Ruby - Wikipedia, the free encyclopedia
Ruby on Rails
Ruby's Diner - rubys.com
Ruby Boutique
Ruby Annotation
[Ruby-Doc.org: Documenting the Ruby Language]

ซึ่งรายชื่อที่ได้จากผลลัพธ์ของการรันโค้ดนั้นจะตรงกับหน้าแรกของการแสดงผลการค้นหาด้วย google พอดี

คลิ๊ก Link บนหน้า web
เมื่อรู้จักการ submit ฟอร์มแล้วลองมาดูกันต่อว่าถ้าต้องการ click link เพื่อไปยังหน้าต่อไปจะทำยังไง
ง่ายมากครับ งานนี้แค่ใช้เมธอดที่ชื่อว่า click ของอ็อบเจกต์ agent โดยให้ใส่ค่าพารามิเตอร์เป็นอ็อบเจกต์ของ link ที่เราต้องการ click ซึ่ง link ที่ว่านี้จะถูกเก็บเป็นอาเรย์อยู่ในหน้าเว็บเพจซึ่งก็คือตัวแปร search_reault_page ที่เราได้จากตัวอย่างที่แล้ว

ลองดูตัวอย่างของการ click link ที่ชื่อว่า "Next" บนหน้าผลลัพธ์จากการค้นหา ในโค้ดต่อไปนี้ครับ
next_page = agent.click(search_result_page.links.select do |l|
  l.text =~ /Next/
end.first )
puts "\nHere is the links contain name 'Ruby' at next page."
next_page.links.each do |link|
  if link.text =~ /Ruby/ then puts link.text end
end

จะเห็นว่าค่าพารามิเตอร์ที่ต้องใส่ให้กับเมธอด click ในบรรทัดที่ 13 ก็คืออ็อบเจกต์ link ที่ได้จากการใช้ regular expression ไปจับเอา link ที่มีชื่อ(link.text) ว่า "Next" นั้นเอง

ผลลัพธ์จากการรันโค้ดจึงออกมาดังนี้
Here is the links contain name 'Ruby' at next page.
Ruby QuickRef
RubyForge: Welcome
Ruby - english
CSS3 Ruby Module
The Ruby Programming Language
Programming Ruby: The Pragmatic Programmer's Guide
Ruby-GNOME2 Project Website - Ruby-GNOME2 Project Website
Ruby Falls

ลองเล่นดูนะครับ

อ้อ

ท่านใดอยากได้ตัวอย่างมากกว่านี้ ลองเข้าไปที่ web Mechanize ครับ มีตัวอย่างให้ลองทดสอบและศึกษากันพอสมควร ที่หน้า Example และ Guide
ท่านใดเล่นแล้วมีเกิด inspiration (ว่าไปนั่นเลยนะ - -'') หรือลองแล้วติดขัดยังไงก็ลองมาพูดคุยแลกเปลี่ยนความคิดเห็นกันได้นะครับ

ไว้คราวหน้าจะมาต่อถึงวิธีการ scrub ข้อมูลบนหน้าเวปแบบง่ายๆ ครับ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น