Singleton mehtod คือเมธอดที่เราสร้างขึ้นมาสำหรับ "อ็อบเจก" ตัวใดตัวหนึ่ง (individual object) เท่านั้น
หมายความว่า นอกจากอ็อบเจกจะมีความสามารถทำโน้นทำนี่ตามเมธอดต่างๆ ที่กำหนดเอาไว้ในคลาสแล้ว เราสามารถกำหนดแบบเจาะจง ให้อ็อบเจกตัวใดตัวหนึ่งมีเมธอดเพิ่มขึ้นมาจากเมธอดเดิมที่มีอยู่แล้วในคลาสได้ด้วย เมธอดที่เราเจาะจงให้กับอ็อบเจกต์นั้นแหละที่เรียกว่า singleton method
วันพุธที่ 15 กันยายน พ.ศ. 2553
วันจันทร์ที่ 6 กันยายน พ.ศ. 2553
แปลง String ให้เป็น Constant
อาจมีหลายๆ ครั้ง ที่เราต้องใส่ค่า argument ที่เป็นค่าคงที่ในการเรียกใช้เมธอดหนึ่งๆ ซึ่งค่าคงที่ ที่ใส่ลงไป อาจมีอยู่หลายค่าขึ้นอยู่กับเงื่อนไขที่เหมาะสม พอเราเขียนโค้ดขึ้นมา ผ่านเงื่อนไขต่างๆ จนได้มาซึ่งค่าของ constant ที่เราต้องการแล้ว กลับพบว่าค่าที่เรากรองได้จากการเงื่อนไขพวก if หรือ swicth มันเป็นสตริงที่มีชื่อเหมือนกับชื่อของ constant หาใช่ constant ไม่
วันอังคารที่ 24 สิงหาคม พ.ศ. 2553
การส่ง message ให้กับอ็อบเจ็ก
หลายท่านคงทราบดีและคุ้นเคยกันอยู่แล้ว กับการเรียกใช้เมธอดจากอ็อบเจกต์ ซึ่งจะทำได้โดยการใช้เครื่องหมายจุด (dot operation)
ถ้าจะว่ากันแบบวิชาการสักนิด การเรียกใช้เมธอดจะเปรียบเสมือนการส่ง message ไปให้กับอ็อบเจกต์ เพื่อบอกให้อ็อบเจกต์ปฏิบัติหรือกระทำการสิ่งใดสิ่งหนึ่งตาม message ที่ถูกส่งออกไปหามัน เราจึงเรียกสิ่งที่อยู่ทางด้านขวาของเครื่องหมายดอทว่า message และเรียกสิ่งที่อยู่ด้านซ้ายของดอทว่า receiver ซึ่งโดยทั่วไปก็คืออ็อบเจกต์ของเรานั่นเอง
เช่น ถ้าเราเรียกเมธอด 100.to_s นั่นหมายความว่าีเรากำลังส่ง message (ที่เป็นเมธอดชื่อ) "to_s" ออกไปหา receiver ซึ่งในที่นี้ก็คือตัวเลข 100
ถามว่าแล้วทำไมต้องมานั่งพิจารณาว่าสิ่งนั้นส่ง message ให้สิ่งนี้ด้วย ทำไมไม่เรียกมันว่าการ เรียกใช้เมธอด อย่างเดียวล่ะ จะแบ่งแยกให้งงทำไม จริงๆ แล้ว เหตุที่ต้องพิจารณาการใช้ dot operation ในลักษณะของการส่ง message ไปที่ receiver ก็เพราะ ในหลายๆ ครั้ง ชื่อของเมธอดที่เราต้องการเรียกใช้นั่น อาจจะไม่มีอยู่จริงในอ็อบเจกต์นั้นๆ ก็ได้ ซึ่งจะส่งผลให้เกิด error ที่ไม่ต้องการหรือไม่คาดคิดหากเมธอดเหล่านั้นถูกเรียกใช้ ดังนั้นจึงเป็นการดีกว่า หากเรามีวิธีการรับมือกับเหตุการณ์ดังกล่าว
การมองเมธอดให้เป็น message ที่ส่งไปหา receiver จะเป็นวิธีหนึ่งที่ช่วยเราแก้ปัญหานี้ได้ โดยเมธอดในภาษา Ruby ที่เกี่ยวข้ิองในการแก้ปัญหานี้ได้แก่ respond_to? และ send
ลองดูตัวอย่างต่อไปนี้นะครับ
เราจะทำอย่างไร ถ้าเราต้องการสั่งให้อ็อบเจกต์ Men ทำการกระโดด เดิน หรือ นั่ง ด้วยการป้อนการกระทำดังกล่าวผ่านลงไปทาง keyboard โดยกำหนดให้โปรแกรมของเรารับค่าสตริงที่ป้อนเข้ามาด้วยเมธอด gets จากนั้น ตัดอักขระ new line ด้วยเมธอด chomp หนึ่งที แล้วเก็บค่าที่ได้ลงใน ตัวแปร request
เราอาจใช้วิธีตรวจสอบว่า สตริงที่รับเข้ามามีค่าตรงกับชื่อของเมธอดที่มีหรือไม่ ถ้าใช่ก็ให้แสดงผลของเมธอดนั้นออกทางหน้าจอดังนี้
class Man
def jump
"I'm jumping"
end
def walk
"I'm walking"
end
def sit
"I'm sitting"
end
end
guy = Man.new
puts "What you want me to do ?"
case gets.chomp
when "jump"; puts guy.jump
when "walk"; puts guy.walk
when "sit"; puts guy.sit
else puts "The man not understand this command"
end
จะเห็นว่าวิธีดังกล่าวอาจทำให้โค้ดของเรายาวมาก หากเราคลาส Men มีเมธอดมากกว่านี้
ทีนี้ ถ้าเรามองการเรียกเมธอด jump, walk หรือ sit เป็นการส่ง message ที่บอกถึง "การกระทำ(method)" ไปให้กับอ็อบเจกต์ดู เราจะเขียนโค้ดใหม่ได้ดังนี้
request = gets.chomp
if guy.respond_to?(request)
puts guy.send(request)
else
puts "The man not understand this command"
end
จากโค้ดข้างต้น จะเห็นว่ามีเมธอดที่มาช่วยเราแก้ปัญกาอยู่ 2 เมธอด คือ เมธอด respond_to? และ send
ในบรรทัดที่ 5 เมธอด respond_to? เป็นเมธอดของคลาส Object ทำหน้าที่ตรวจสอบว่า เราสามารถเรียกใช้เมธอดที่เป็นพารามิเตอร์ของมันอยู่จากคลาสนั้นๆ ได้หรือไม่ โดยจะคืนค่าจริงถ้าสามารถเรียกเมธอดจากคลาสนั้นได้ (แสดงว่ามีเมธอดอยู่จริง)
และหัวใจของโค้ดนี้ก็อยู่ที่เมธอด send ในบรรทัดที่ 6 นี่ละครับ โดยเมธอดนี้จะทำหน้าที่เหมือนกับเป็น dot operator เลย แต่แทนที่จะมองว่ามันจะ "เรียก" เมธอดออกมาใช้ตรงๆ คราวนี้เราจะมองว่ามัน "ส่ง" message ที่มีค่าเป็นชื่อเมธอด ไป "เรียก" เมธอดตัวนั้นออกมาใช้
อย่างไรก็ตาม มีข้อควรระวังในการใช้ send เหมือนกันครับ
ถึงแม้ว่าเมธอด send จะเป็นเมธอดของคลาส Object ที่เราแทบจะสามารถเรียกใช้มันได้จากทุกอ็อบเจกต์ (เพราะอ็อบเจกต์แทบทุกตัวล้วนสืบทอดมาจากคลาส Object) แต่ชื่อของมันก็อาจจะไปซ้ำกับเมธอดอื่นที่มีชื่อว่า "send" ได้เหมือนกัน ซึ่งน่าจะมีโอกาสซ้ำสูงซะด้วย เพราะเราอาจตั้งชื่อเมธอดในคลาสของเราว่า send แต่ใช้ส่งข้อมูลอย่างอื่นก็ได้
แต่ Ruby ก็มีมี alias สำหรับเมธอด send เอาไว้กันพลาดแล้ว ซึ่งก็คือเมธอดชื่อ "__send__" นั่นเอง
ดังนั้นหากจะนำหลักการส่ง message ไปยัง receiver มาใช้ก็ให้คิดถึง เมธอด __send__ เอาไว้แล้วกันครับ
วันศุกร์ที่ 16 กรกฎาคม พ.ศ. 2553
Matz Keynote จาก European Ruby Conference ครั้งล่าสุด
เพิ่งไปเจอ clip นี้ ที่เวปของ Euruko 2010
เป็น keynote ของ Matz
เป็น keynote ของ Matz
วันอังคารที่ 2 กุมภาพันธ์ พ.ศ. 2553
แปลงซอร์ซไฟล์ Ruby ให้เป็น .exe
จริงอยู่ที่เราสามารถรันซอร์ซไฟล์ .rb เพื่อเรียกโปรแกรมที่เขียนขึ้นมาใช้ได้เลย แต่มันมีเงือนไขอยู่ที่ว่าเครื่องของเราต้องมี Ruby intepreter และมันต้องรู้จักไฟล์ .rb ด้วยนะ อันนี้ถ้าเราลง Ruby installer หรือ Ruby package ไปแล้วก็ไม่มีปัญหา แต่ถ้าสมมติว่าจะเอาโปรแกรมที่เขียนด้วย Ruby ไปรันที่เครื่องอื่น(สมมติว่าจะรันบน Windows นะ)ที่ไม่มี Ruby ล่ะจะทำยังไง ...ทางเลือกหนึ่งก็คือแปลงซอร์ซไฟล์ .rb ให้เป็น .exe ครับ ซึ่งวันนี้เราจะมาดูกันว่ามันมีวิธีการทำอย่างไร
เครื่องมือ?
ณ ตอนนี้มี gems อยู่ 2 ตัวที่ผมรู้จักที่สามารถใช้ในการแปลงไฟล์เป็น .exe ซึ่งได้แก่ rubyscript2exe และ ocra
ทั้ง 2 ตัวนี้ผมเคยใช้มาแล้วครับ ขอเล่าประสบการณ์ให้ฟังหน่อยแล้วกัน
ผมเข้าใจว่า rubyscript2exe น่าจะมีปัญหากับ version ของ RubyGems นั่นคือมันไม่สามารถใช้กับ RubyGems version > 1.2.0 (ขณะนี้ version ล่าสุดของ RubyGems คือ 1.3.5) แต่จะให้ผมลง Ruby กับ RubyGems ใหม่เพื่อทดสอบนั้นคงไม่ดีกว่าครับ กลัว gems ตัวอื่นๆของผมจะเดี้ยงไปด้วย ฮา
หากมีท่านใดอาสาช่วยผมทดลองก็จะขอบคุณมากๆเลยครับ ถ้าใช้งานได้ล่ะก็อย่าลืมเอาผลมาบอกกันบ้างนะครับ
ใครอยากลอง rubyscript2exe ก็สามารถ install ผ่าน gems ได้เลยด้วยคำสั่ง
ส่วนการใช้งานเมื่อค้องการแปลงไฟล์เป็น .exe ก็ใช้ดังนั้นครับ(สำหรับท่านที่ install ด้วย RubyGem เท่านั้นนะครับ)
สำหรับรายละเอียดของการใช้งานรวมถึง option ต่างๆของ rubyscript2exe นั้นสามารุเข้าไปดูได้ที่ official website ของ rubyscript2exe ครับ
เท่าที่ผมใช้งานมานั้นยังไม่เจอปัญหาหรือ error ใดๆกับเจ้า Ocra เลยครับ ผมจึงขอแนะนำท่านที่ต้องการแปลงไฟล์เป็น .exe ลองใช้ดูนะครับ ของเขาดีจริงๆ
Ocra นั้นมาเป็น RubyGem แพกเกจครับดังนั้นเราสามารถติดตั้งได้โดยใช้คำสั่ง
ส่วนวิธีการใช้งานนั้นก็ไม่ยาก พิมพ์คำสั่ง ocra แล้วตามด้วยชื่อไฟล์ .rb ที่เราต้องการแปลง
ผมขอแสดงตัวอย่างของการแปลงซอร์ซไฟล์ .rb ไปเป็น .exe โดยใช้ ocra สักตัวอย่างนะครับ โดยผมสมมติว่าซอร์ซไฟล์ของผมชื่อ test_ocra.rb ซึ่งมีหน้าตาดังนี้นะครับ
ดังนั้นผมสามารถแปลงไฟล์ซอร์ซโค้ดดังกล่าวให้เป็นไฟล์ .exe ได้ด้วยคำสั่งต่อไปนี้
จากนั้น ocra จะทำการ complie ซอร์ซไฟล์ของเราและตรวจสอบ include ไฟล์ต่างๆ(ถ้ามี)
ซึ่งตรงนี้เราจะเห็นโปรแกรมของเรารันขึ้นมาก็ไม่ต้องตกใจให้ปิดมันลงไปซะ เพื่อให้ ocra ทำการ Build ไฟล์ของเราต่อไป
ซึ่งจะได้ผมลัพธ์ดังนี้
เท่านี้ก็เป็นอันเสร็จสิ้น เราจะได้ไฟล์ test_ocra.exe ที่ต้องการออกมา
เมื่อลองรันไฟล์ .exe ดูก็จะได้ผลลัพธ์ดังนี้
ไม่ยากเลยใช้ไหมครับ
คุณสามารถเข้าไปดูรายละเอียดของการใช้งาน ocra นอกเหนือจากที่ผมได้นำเสนอไว้ในวันนี้ได้ที่ Official website ของ Ocra นะครับ
อย่างไรก็ตาม การทำซอร์ซไฟล์ .rb ให้เป็น .exe ด้วย Ocra หรือ Rubyscript2exe อาจไม่ใช้ทางเลือกที่ดีที่สุด เพราะข้อเสียที่เห็นได้ชัดเจนคือขนาดของไฟล์ exe หลังจากที่แปลงไฟล์แล้วนั้นมีขนาดใหญ่โตจริงๆครับ ไฟล์ test_ocra.exe จากตัวอย่างข้างต้นที่เป็นแค่โปรแกรม hello ธรรมดาๆยังปาเข้าไปกว่า 500K แล้วครับ แต่ถ้าเป็นโปรแกรม hello เหมือนกันแต่เป็น GUI โดยเขียนภายใต้ไลบรารี WxRuby นั้นหลังจากแปลงไฟล์เป็น .exe แล้วขนาดของไฟล์จะใหญ่ถึง 2.6M เลยทีเดียว
อันนี้ถือว่าเป็นโจทย์ข้อสำคัญของภาษา Ruby เหมือนกันครับ หากต้องการใช้ application ที่พัฒนาด้วยภาษา Ruby ถูกนำไปใช้อย่างจริงจังในตลาด
แล้วมีทางเลือกอื่นไหม ถ้ายังอยากนำ app ที่เขียนด้วย Ruby ไปใช้?
ถามผมตอนนี้คงตอบว่า ให้ไปลอง JRuby ดูครับ เพราะมันรันบน JVM มันควรจะมีวิธีการที่สามารถนำไปใช้ได้กว้างกว่ารึเปล่า
ยังไม่เคยศึกษาอย่างจริงจังเหมือนกัน
ท่านใดรู้กรุณาบอกเป็นวิทยาทานทีนะคร้าบ(ซะงั้น - -'')
เครื่องมือ?
ณ ตอนนี้มี gems อยู่ 2 ตัวที่ผมรู้จักที่สามารถใช้ในการแปลงไฟล์เป็น .exe ซึ่งได้แก่ rubyscript2exe และ ocra
ทั้ง 2 ตัวนี้ผมเคยใช้มาแล้วครับ ขอเล่าประสบการณ์ให้ฟังหน่อยแล้วกัน
Rubyscript2exe
rubyscript2exe เป็น gems ตัวแรกที่ผมได้มีโอกาสทดลองใช้การแปลงไฟล์ครับ แล้วก็เคยประสบความสำเร็จในการใช้มันเมื่อนานมาแล้วด้วย(เย้) แต่มีอยู่วันหนึ่งมีเหตุให้ผมต้องลง Ruby และ RubyGem บนเครื่องใหม่ ปรากฏว่าหลังจากวันนั้นผมก็ไม่สามารถใช้เจ้า rubyscript2exe เพื่อแปลงไฟล์ให้ผมได้อีกเลย มันพ่น error message ตลอดเวลาที่ผมพยายามจะ complie มัน เคยพยายามหา solution จาก webboard ต่างๆก็แล้วแต่ก็ไม่ได้ช่วยแก้ปัญหาเลยครับ ทำเอาผมปวดหัวอยู่หลายวันผมเข้าใจว่า rubyscript2exe น่าจะมีปัญหากับ version ของ RubyGems นั่นคือมันไม่สามารถใช้กับ RubyGems version > 1.2.0 (ขณะนี้ version ล่าสุดของ RubyGems คือ 1.3.5) แต่จะให้ผมลง Ruby กับ RubyGems ใหม่เพื่อทดสอบนั้นคงไม่ดีกว่าครับ กลัว gems ตัวอื่นๆของผมจะเดี้ยงไปด้วย ฮา
หากมีท่านใดอาสาช่วยผมทดลองก็จะขอบคุณมากๆเลยครับ ถ้าใช้งานได้ล่ะก็อย่าลืมเอาผลมาบอกกันบ้างนะครับ
ใครอยากลอง rubyscript2exe ก็สามารถ install ผ่าน gems ได้เลยด้วยคำสั่ง
C:\gem install rubyscript2exe
ส่วนการใช้งานเมื่อค้องการแปลงไฟล์เป็น .exe ก็ใช้ดังนั้นครับ(สำหรับท่านที่ install ด้วย RubyGem เท่านั้นนะครับ)
C:\>rubyscript2exe your_code.rb
สำหรับรายละเอียดของการใช้งานรวมถึง option ต่างๆของ rubyscript2exe นั้นสามารุเข้าไปดูได้ที่ official website ของ rubyscript2exe ครับ
Ocra
เมื่อผิดหวังจาก rubyscript2exe แล้วผมก็เริ่มค้นหาครับว่ามีตัวช่วยอื่รหรือไม่ แล้วในที่สุดผมก็เจอครับ ซึ่งก็คือ gem ที่ชื่อ Ocra นั่นเองเท่าที่ผมใช้งานมานั้นยังไม่เจอปัญหาหรือ error ใดๆกับเจ้า Ocra เลยครับ ผมจึงขอแนะนำท่านที่ต้องการแปลงไฟล์เป็น .exe ลองใช้ดูนะครับ ของเขาดีจริงๆ
Ocra นั้นมาเป็น RubyGem แพกเกจครับดังนั้นเราสามารถติดตั้งได้โดยใช้คำสั่ง
C:\gem install ocra
ส่วนวิธีการใช้งานนั้นก็ไม่ยาก พิมพ์คำสั่ง ocra แล้วตามด้วยชื่อไฟล์ .rb ที่เราต้องการแปลง
ผมขอแสดงตัวอย่างของการแปลงซอร์ซไฟล์ .rb ไปเป็น .exe โดยใช้ ocra สักตัวอย่างนะครับ โดยผมสมมติว่าซอร์ซไฟล์ของผมชื่อ test_ocra.rb ซึ่งมีหน้าตาดังนี้นะครับ
puts "Hello Ocra"
STDIN.getc
ดังนั้นผมสามารถแปลงไฟล์ซอร์ซโค้ดดังกล่าวให้เป็นไฟล์ .exe ได้ด้วยคำสั่งต่อไปนี้
C:\ocra test_ocra.rb
จากนั้น ocra จะทำการ complie ซอร์ซไฟล์ของเราและตรวจสอบ include ไฟล์ต่างๆ(ถ้ามี)
ซึ่งตรงนี้เราจะเห็นโปรแกรมของเรารันขึ้นมาก็ไม่ต้องตกใจให้ปิดมันลงไปซะ เพื่อให้ ocra ทำการ Build ไฟล์ของเราต่อไป
ซึ่งจะได้ผมลัพธ์ดังนี้
=== Loading script to check dependencies
Hello Ocra
a
=== Building test_ocra.exe
m src
a src\test_ocra.rb
m bin
a bin\ruby.exe
a bin\msvcrt-ruby18.dll
a bin\zlib1.dll
m lib
m lib\ruby
m lib\ruby\gems
m lib\ruby\gems\1.8
m lib\ruby\gems\1.8\specifications
a lib\ruby\gems\1.8\specifications\ocra-1.1.3.gemspec
m lib\ruby\site_ruby
m lib\ruby\site_ruby\1.8
m lib\ruby\site_ruby\1.8\rubygems
a lib\ruby\site_ruby\1.8\rubygems\defaults.rb
m lib\ruby\1.8
m lib\ruby\1.8\i386-mswin32
a lib\ruby\1.8\i386-mswin32\thread.so
a lib\ruby\1.8\thread.rb
a lib\ruby\1.8\i386-mswin32\etc.so
a lib\ruby\1.8\i386-mswin32\rbconfig.rb
a lib\ruby\site_ruby\1.8\rubygems\exceptions.rb
a lib\ruby\site_ruby\1.8\rubygems\requirement.rb
a lib\ruby\site_ruby\1.8\rubygems\version.rb
a lib\ruby\site_ruby\1.8\rubygems\dependency.rb
a lib\ruby\site_ruby\1.8\rubygems\gem_path_searcher.rb
a lib\ruby\site_ruby\1.8\rubygems\user_interaction.rb
a lib\ruby\site_ruby\1.8\rubygems\platform.rb
a lib\ruby\site_ruby\1.8\rubygems\specification.rb
a lib\ruby\site_ruby\1.8\rubygems\source_index.rb
a lib\ruby\site_ruby\1.8\rubygems\builder.rb
a lib\ruby\1.8\i386-mswin32\stringio.so
m lib\ruby\1.8\yaml
a lib\ruby\1.8\yaml\error.rb
a lib\ruby\1.8\i386-mswin32\syck.so
a lib\ruby\1.8\yaml\ypath.rb
a lib\ruby\1.8\yaml\basenode.rb
a lib\ruby\1.8\yaml\syck.rb
a lib\ruby\1.8\yaml\tag.rb
a lib\ruby\1.8\yaml\stream.rb
a lib\ruby\1.8\yaml\constants.rb
a lib\ruby\1.8\rational.rb
m lib\ruby\1.8\date
a lib\ruby\1.8\date\format.rb
a lib\ruby\1.8\date.rb
a lib\ruby\1.8\yaml\rubytypes.rb
a lib\ruby\1.8\yaml\types.rb
a lib\ruby\1.8\yaml.rb
a lib\ruby\1.8\i386-mswin32\Win32API.so
a lib\ruby\site_ruby\1.8\rubygems\config_file.rb
a lib\ruby\site_ruby\1.8\rubygems\custom_require.rb
a lib\ruby\1.8\fileutils.rb
a lib\ruby\site_ruby\1.8\rubygems.rb
a lib\ruby\site_ruby\1.8\ubygems.rb
m lib\ruby\site_ruby\1.8\i386-msvcrt
a lib\ruby\site_ruby\1.8\i386-msvcrt\zlib.so
a lib\ruby\1.8\i386-mswin32\socket.so
a lib\ruby\1.8\timeout.rb
m lib\ruby\1.8\net
a lib\ruby\1.8\net\protocol.rb
m lib\ruby\1.8\uri
a lib\ruby\1.8\uri\common.rb
a lib\ruby\1.8\uri\generic.rb
a lib\ruby\1.8\uri\ftp.rb
a lib\ruby\1.8\uri\http.rb
a lib\ruby\1.8\uri\https.rb
a lib\ruby\1.8\uri\ldap.rb
a lib\ruby\1.8\uri\mailto.rb
a lib\ruby\1.8\uri.rb
a lib\ruby\1.8\net\http.rb
a lib\ruby\1.8\parsedate.rb
a lib\ruby\1.8\time.rb
a lib\ruby\site_ruby\1.8\rubygems\remote_fetcher.rb
a lib\ruby\site_ruby\1.8\rubygems\spec_fetcher.rb
e RUBYOPT -rubygems
e RUBYLIB
e GEM_PATH \gemhome
l bin\ruby.exe ruby.exe " \src\test_ocra.rb"
=== Compressing
=== Finished (Final size was 505569)
Hello Ocra
a
=== Building test_ocra.exe
m src
a src\test_ocra.rb
m bin
a bin\ruby.exe
a bin\msvcrt-ruby18.dll
a bin\zlib1.dll
m lib
m lib\ruby
m lib\ruby\gems
m lib\ruby\gems\1.8
m lib\ruby\gems\1.8\specifications
a lib\ruby\gems\1.8\specifications\ocra-1.1.3.gemspec
m lib\ruby\site_ruby
m lib\ruby\site_ruby\1.8
m lib\ruby\site_ruby\1.8\rubygems
a lib\ruby\site_ruby\1.8\rubygems\defaults.rb
m lib\ruby\1.8
m lib\ruby\1.8\i386-mswin32
a lib\ruby\1.8\i386-mswin32\thread.so
a lib\ruby\1.8\thread.rb
a lib\ruby\1.8\i386-mswin32\etc.so
a lib\ruby\1.8\i386-mswin32\rbconfig.rb
a lib\ruby\site_ruby\1.8\rubygems\exceptions.rb
a lib\ruby\site_ruby\1.8\rubygems\requirement.rb
a lib\ruby\site_ruby\1.8\rubygems\version.rb
a lib\ruby\site_ruby\1.8\rubygems\dependency.rb
a lib\ruby\site_ruby\1.8\rubygems\gem_path_searcher.rb
a lib\ruby\site_ruby\1.8\rubygems\user_interaction.rb
a lib\ruby\site_ruby\1.8\rubygems\platform.rb
a lib\ruby\site_ruby\1.8\rubygems\specification.rb
a lib\ruby\site_ruby\1.8\rubygems\source_index.rb
a lib\ruby\site_ruby\1.8\rubygems\builder.rb
a lib\ruby\1.8\i386-mswin32\stringio.so
m lib\ruby\1.8\yaml
a lib\ruby\1.8\yaml\error.rb
a lib\ruby\1.8\i386-mswin32\syck.so
a lib\ruby\1.8\yaml\ypath.rb
a lib\ruby\1.8\yaml\basenode.rb
a lib\ruby\1.8\yaml\syck.rb
a lib\ruby\1.8\yaml\tag.rb
a lib\ruby\1.8\yaml\stream.rb
a lib\ruby\1.8\yaml\constants.rb
a lib\ruby\1.8\rational.rb
m lib\ruby\1.8\date
a lib\ruby\1.8\date\format.rb
a lib\ruby\1.8\date.rb
a lib\ruby\1.8\yaml\rubytypes.rb
a lib\ruby\1.8\yaml\types.rb
a lib\ruby\1.8\yaml.rb
a lib\ruby\1.8\i386-mswin32\Win32API.so
a lib\ruby\site_ruby\1.8\rubygems\config_file.rb
a lib\ruby\site_ruby\1.8\rubygems\custom_require.rb
a lib\ruby\1.8\fileutils.rb
a lib\ruby\site_ruby\1.8\rubygems.rb
a lib\ruby\site_ruby\1.8\ubygems.rb
m lib\ruby\site_ruby\1.8\i386-msvcrt
a lib\ruby\site_ruby\1.8\i386-msvcrt\zlib.so
a lib\ruby\1.8\i386-mswin32\socket.so
a lib\ruby\1.8\timeout.rb
m lib\ruby\1.8\net
a lib\ruby\1.8\net\protocol.rb
m lib\ruby\1.8\uri
a lib\ruby\1.8\uri\common.rb
a lib\ruby\1.8\uri\generic.rb
a lib\ruby\1.8\uri\ftp.rb
a lib\ruby\1.8\uri\http.rb
a lib\ruby\1.8\uri\https.rb
a lib\ruby\1.8\uri\ldap.rb
a lib\ruby\1.8\uri\mailto.rb
a lib\ruby\1.8\uri.rb
a lib\ruby\1.8\net\http.rb
a lib\ruby\1.8\parsedate.rb
a lib\ruby\1.8\time.rb
a lib\ruby\site_ruby\1.8\rubygems\remote_fetcher.rb
a lib\ruby\site_ruby\1.8\rubygems\spec_fetcher.rb
e RUBYOPT -rubygems
e RUBYLIB
e GEM_PATH \gemhome
l bin\ruby.exe ruby.exe " \src\test_ocra.rb"
=== Compressing
=== Finished (Final size was 505569)
เท่านี้ก็เป็นอันเสร็จสิ้น เราจะได้ไฟล์ test_ocra.exe ที่ต้องการออกมา
เมื่อลองรันไฟล์ .exe ดูก็จะได้ผลลัพธ์ดังนี้
ไม่ยากเลยใช้ไหมครับ
คุณสามารถเข้าไปดูรายละเอียดของการใช้งาน ocra นอกเหนือจากที่ผมได้นำเสนอไว้ในวันนี้ได้ที่ Official website ของ Ocra นะครับ
อย่างไรก็ตาม การทำซอร์ซไฟล์ .rb ให้เป็น .exe ด้วย Ocra หรือ Rubyscript2exe อาจไม่ใช้ทางเลือกที่ดีที่สุด เพราะข้อเสียที่เห็นได้ชัดเจนคือขนาดของไฟล์ exe หลังจากที่แปลงไฟล์แล้วนั้นมีขนาดใหญ่โตจริงๆครับ ไฟล์ test_ocra.exe จากตัวอย่างข้างต้นที่เป็นแค่โปรแกรม hello ธรรมดาๆยังปาเข้าไปกว่า 500K แล้วครับ แต่ถ้าเป็นโปรแกรม hello เหมือนกันแต่เป็น GUI โดยเขียนภายใต้ไลบรารี WxRuby นั้นหลังจากแปลงไฟล์เป็น .exe แล้วขนาดของไฟล์จะใหญ่ถึง 2.6M เลยทีเดียว
อันนี้ถือว่าเป็นโจทย์ข้อสำคัญของภาษา Ruby เหมือนกันครับ หากต้องการใช้ application ที่พัฒนาด้วยภาษา Ruby ถูกนำไปใช้อย่างจริงจังในตลาด
แล้วมีทางเลือกอื่นไหม ถ้ายังอยากนำ app ที่เขียนด้วย Ruby ไปใช้?
ถามผมตอนนี้คงตอบว่า ให้ไปลอง JRuby ดูครับ เพราะมันรันบน JVM มันควรจะมีวิธีการที่สามารถนำไปใช้ได้กว้างกว่ารึเปล่า
ยังไม่เคยศึกษาอย่างจริงจังเหมือนกัน
ท่านใดรู้กรุณาบอกเป็นวิทยาทานทีนะคร้าบ(ซะงั้น - -'')
วันอังคารที่ 19 มกราคม พ.ศ. 2553
ดูดการ์ตูนจากเว็ป onemanga ด้วย Ruby Mechanize
หลังจากได้รู้จักกับ Ruby Mechanize ไปบ้างแล้ว คราวนี้มาดูตัวอย่างการนำไปใช้งานกันบ้าง ซึ่งผมก็มี project เล็กๆเป็น case ตัวอย่างที่อยากนำเสนอครับ น่าจะเป็น project ที่คนรักการ์ตูนต้องอยากเอาไปลองเล่นแน่ๆ
Onemanga เว็ปการ์ตูนออนไลน์อันดับหนึ่งของผม
งานที่เราจะนำ Ruby Mechanize มาใช้ในวันนี้เป็นการไล่เก็บการ์ตูนที่ถูกสแกนแล้วนำมาโพสเอาไว้ให้เพื่อนๆในเน็ตได้อ่านกันแบบออนไลน์ ซึ่งเว็บที่มีคนสแกนการ์ตูนให้อ่านนั้นมีอยู่ไม่น้อเหมือนกันแต่ที่ผมใช้บริการบ่อยๆก็ต้องที่ Onemanga ครับ เพราะการ์ตูนเยอะ อัพเดตค่อนข้างเร็วและคุณภาพของรูปที่สแกนก็อยู่ในขั้นใช้ได้ทีเดียว แถมได้ฝึกภาษาองกฤษด้วยเพราะแปลจากญี่ปุ่นเป็นอังกฤษเรียบร้อยแล้ว
เว็ป Onemanga จะอนุญาตให้เราอ่านการ์ตูนได้ทุกเรื่องครับแต่จะอ่านได้แบบออนไลน์เท่านั้นคือ click เปิดดูรูปไปทีละหน้าๆ ไม่สามารถ download ไฟล์รูปของการ์ตูนเรื่องนั้นทีเดียวได้ นั้นคือถ้าเราอยากเก็บไฟล์รูปของการ์ตูนเรื่องที่เราชอบจากเว็ปนี้เราต้องใช้วิธี save as หน้าการ์ตูนโดยการคลิ๊กขวาเท่านั้น ถ้าเรื่องนึงเอาแบบสั้นๆเลยนะมีซัก 10 ตอน ตอนละ 20 หน้า คงต้องคลิ้กแล้วโหลดเว็บกันทีละหน้าถึง 200 ครั้ง แบบนี้ไม่ดีแน่ แต่อย่าเพิ่งหมดหวังครับ เราจะมาดูกันว่า Ruby Mechanize จะช่วยจัดการกับปัญหานี้ได้อย่างไร
ทำความเข้าใจขั้นตอนปกติด้วยการ save as กันก่อน
ก่อนอื่นเราไปดูวิธีการ save รูปจากการ์ตูนเรื่องที่เราสนใจในเว็ปนี้แบบปกติกันก่อน เมื่อทำความเข้าใจแล้วจึงค่อยเขียนโค้ดให้ทำขั้นตอนเหล่านั้นให้โดยอัตโนมัติอีกที
1) ที่หน้าแรกของเว็ปเราจะเห็นรายชื่อการ์ตูนที่อัพเดตใหม่ในแต่ละวัน แต่เพื่อความง่ายต่อการค้นหาการ์ตูนเรื่องที่ต้องการเราจะใส่ชื่อการ์ตูนลงไปใน input text box ตรงมุมบนขวาแล้วคลิ๊กปุ่ม search ซึ่งผมจะกำหนดให้ชื่อของการ์ตูนที่เรานำไป search นั้นเป็นพารามิเตอร์ตัวหนึ่งที่ต้องใส่เวลาเรารันโค้ด ruby ด้วย
ในตัวอย่างนี้ผมจะลองค้นหาเรื่อง Naruto ละกันครับ
2) หน้าของเว็ปจะโชว์เรื่อง Naruto ถ้าหากว่ามีการ์ตูนเรื่องนี้อยู่จริง
เมื่อผมคลิ๊กตาม link ชื่อ Naruto แล้วหน้าของเว็ปโชว์จำนวนตอนทั้งหมดของการ์ตูนเรื่องนี้
ถ้าผมลองคลิ๊กตอนใดตอนหนึ่งดูผมก็จะเข้าสู่หน้าของการยืนยันก่อนการการ์ตูนในตอนนั้นๆเสมอ ซึ่งคุณผู้อ่านจะสังเกตุได้ว่า url ของเราจะอยู่ในรูปแบบ "http://www.onemanga.com/ชื่อเรื่อง/ตอนที่/" ซึ่งในที่นี้จะเป็น ดังนั้นผมจึงขอกำหนดให้ "ตอนที่" เป็นพารามิเตอร์อีกตัวหนึ่งของโค้ดด้วย
3) เมื่อคลิ๊กเลือกตอนที่ต้องการอ่านแล้วเราจะเข้าสู่หน้ายืนยันเพื่อเริ่มอ่าน ก็ให้เราคลิ๊กไปที่ "Beginning ชื่อเรื่อง ตอนที่"
4) หน้าเว็บจะโชว์รูป scan หน้าแรกของตอนนั้นๆ ซึ่งสามารถ save รูปสแกนได้โดยการคลิ๊กขวาแล้วเลือก save as เท่านั้น ถ้าจะอ่านหน้าถัดไปเราก็คลื๊กปุ่ม next หรือคลิ๊กไปที่รูปได้เลย ในหน้านี้จะมี drop down box ที่ชื่อว่า "Page" อยู่ด้านบนของรูป scan ด้วยซึ่งมันจะแสดงจำนวนหน้าทั้งหมดภายในตอนนั้นๆ เราจะใช้จำนวนหน้าตัวนี้
ได้เวลาของโค้ด Ruby แล้ว
เราจะทำ 4 ขั้นตอนข้างต้นแบบอัตโนมัติโดยใช้โค้ด ruby และความสามารถของไลบรารี Mechanize จากที่เคยพูดไปใน blog ก่อนหน้านี้เข้าช่วย ซึ่งโค้ดของผมมีหน้าตาแบบนี้ครับ
จะเห็นว่าโค้ดนี้ต้องการพารามิเตอร์ 2 ตัวด้วยกันซึ่งก็คือ "ชื่อเรื่อง" และ "ตอนที่" ซึ่งค่าทั้งสองจะถูกเก็บอยู่ในตัวแปรที่ชื่อ series และ chapter ตามลำดับ
จากโค้ดข้างตันคุณผู้อ่านจะได้เห็นตัวอย่างของการใช้เมธอดต่างๆ ของอ็อบเจกต์จากคลาส WWW::Mechanize ซึ่งตัวหลักๆที่ใช้ในโค้ดนี้ได้แก่
1) เมธอด get ซึ่งจะรับค่าเป็น url และจะคืนค่าออกมาเป็นอ็อบเจกต์ Page ซึ่งเก็บ content ของเว็บเพจตาม url ที่เราใส่ลงไปทั้งหมด อ็อบเจกต์ Page จึงเปรียบเสมือนหน้าเว็ปจริงๆ ที่เราสามารถที่จะดำเนินการใดๆกับมันต่อไปก็ได้เช่น แสดง link ทั้งหมดที่อยู่ในหน้านั้นด้วยเมธอด links หรือกรอกแบบฟอร์มและ submit เป็นต้น
2) เมธอด click ซึ่งใช้เปลี่ยนหน้าเว็บเพจไปยัง link ที่ต้องการ โดยพารามิเตอร์ของเมธอดนี้จะต้องเป็นอ็อบเจกต์ link นะครับไม่ใช่ url(ลองดูโค้ดบรรทัดที่ 43 อ็อบเจกต์ link นั้นได้มาจากการเรียกใช้เมธอด links ของอ็อบเจกต์ Page อีกที)
3) เมธอด search โดยเมธอดนี้จะทำการค้นหาโหนดที่เราต้องการในหน้าเว็บเพจนั้นๆ ซึ่งโหนดที่เป็นพารามิเตอร์ของเมธอดนี้นั้นเราสามารถใส่มาในรูปของ html node, css node หรือ xpath node ก็ได้ จากโค้ดจะพบค่าของโหนดที่ผมใส่เป็นพารามิเตอร์ให้กับเมธอด search ในบรรทัดที่ 48 นั้นคือ 'select#id_page_select.page-select option' ซึ่งมันคือค่าโหนดของ dropdown box ที่ชื่อ Page นั่นเอง ผมนำค่าโหนดนี้มาจากโปรแกรม firebug ครับ โดยการเข้าไปที่โหมด firebug แล้วใช้เม้าท์จิ้มไปที่ component ที่เราต้องการรู้โหนด ในที่นี้คือ dropdown box จากนั้น ค่าของโหนดจะถูกแสดงขึ้นที่หน้าต่างของโปรแกรม firebug ลองเล่นดูนะครับ... ค่าที่คืนค่าออกมาจากเมธอด search จะเป็นอ็อบเจกต์ของคลาส Nokogiri::XML::Node ครับ ซึ่งสามารถนำไปใช้ประโยชน์ต่อได้อีกมากมายเช่นหาค่าที่เก็บอยู่ใน node นั้นหรือค่าที่อยู่ใน node แม่ ของมัน ฯลฯ อันนี้จะค่อนข้างเวียนหัวนิดนึงต้องค่อยๆทำความเข้าใจไปนะครับ ผมก็ยังงงๆ อยู่เลย
ผลที่ได้หลังจากทดลองรันโค้ด scrub_onemanga.rb จะปรากฏดังรูปด้านล่างนี้ แล้วเราก็จะได้รูป scan ของตอนนั้นๆของการ์ตูนเรื่องที่เราค้นหาครับ
เป็นอย่างไรกันบ้างครับ
หวังว่าคุณผู้อ่านจะได้ไอเดียในการนำ Ruby Mechanize ไปใช้งานหรือต่อยอดกับโปรเจกของคุณได้บ้าง
ใครมีประสบการณ์หรือไอเดียเจ๋งที่อยากจะแชร์กันก็ลอง post เข้ามาพูดคุยกันดูนะครับ
Onemanga เว็ปการ์ตูนออนไลน์อันดับหนึ่งของผม
งานที่เราจะนำ Ruby Mechanize มาใช้ในวันนี้เป็นการไล่เก็บการ์ตูนที่ถูกสแกนแล้วนำมาโพสเอาไว้ให้เพื่อนๆในเน็ตได้อ่านกันแบบออนไลน์ ซึ่งเว็บที่มีคนสแกนการ์ตูนให้อ่านนั้นมีอยู่ไม่น้อเหมือนกันแต่ที่ผมใช้บริการบ่อยๆก็ต้องที่ Onemanga ครับ เพราะการ์ตูนเยอะ อัพเดตค่อนข้างเร็วและคุณภาพของรูปที่สแกนก็อยู่ในขั้นใช้ได้ทีเดียว แถมได้ฝึกภาษาองกฤษด้วยเพราะแปลจากญี่ปุ่นเป็นอังกฤษเรียบร้อยแล้ว
เว็ป Onemanga จะอนุญาตให้เราอ่านการ์ตูนได้ทุกเรื่องครับแต่จะอ่านได้แบบออนไลน์เท่านั้นคือ click เปิดดูรูปไปทีละหน้าๆ ไม่สามารถ download ไฟล์รูปของการ์ตูนเรื่องนั้นทีเดียวได้ นั้นคือถ้าเราอยากเก็บไฟล์รูปของการ์ตูนเรื่องที่เราชอบจากเว็ปนี้เราต้องใช้วิธี save as หน้าการ์ตูนโดยการคลิ๊กขวาเท่านั้น ถ้าเรื่องนึงเอาแบบสั้นๆเลยนะมีซัก 10 ตอน ตอนละ 20 หน้า คงต้องคลิ้กแล้วโหลดเว็บกันทีละหน้าถึง 200 ครั้ง แบบนี้ไม่ดีแน่ แต่อย่าเพิ่งหมดหวังครับ เราจะมาดูกันว่า Ruby Mechanize จะช่วยจัดการกับปัญหานี้ได้อย่างไร
ทำความเข้าใจขั้นตอนปกติด้วยการ save as กันก่อน
ก่อนอื่นเราไปดูวิธีการ save รูปจากการ์ตูนเรื่องที่เราสนใจในเว็ปนี้แบบปกติกันก่อน เมื่อทำความเข้าใจแล้วจึงค่อยเขียนโค้ดให้ทำขั้นตอนเหล่านั้นให้โดยอัตโนมัติอีกที
1) ที่หน้าแรกของเว็ปเราจะเห็นรายชื่อการ์ตูนที่อัพเดตใหม่ในแต่ละวัน แต่เพื่อความง่ายต่อการค้นหาการ์ตูนเรื่องที่ต้องการเราจะใส่ชื่อการ์ตูนลงไปใน input text box ตรงมุมบนขวาแล้วคลิ๊กปุ่ม search ซึ่งผมจะกำหนดให้ชื่อของการ์ตูนที่เรานำไป search นั้นเป็นพารามิเตอร์ตัวหนึ่งที่ต้องใส่เวลาเรารันโค้ด ruby ด้วย
ในตัวอย่างนี้ผมจะลองค้นหาเรื่อง Naruto ละกันครับ
2) หน้าของเว็ปจะโชว์เรื่อง Naruto ถ้าหากว่ามีการ์ตูนเรื่องนี้อยู่จริง
เมื่อผมคลิ๊กตาม link ชื่อ Naruto แล้วหน้าของเว็ปโชว์จำนวนตอนทั้งหมดของการ์ตูนเรื่องนี้
ถ้าผมลองคลิ๊กตอนใดตอนหนึ่งดูผมก็จะเข้าสู่หน้าของการยืนยันก่อนการการ์ตูนในตอนนั้นๆเสมอ ซึ่งคุณผู้อ่านจะสังเกตุได้ว่า url ของเราจะอยู่ในรูปแบบ "http://www.onemanga.com/ชื่อเรื่อง/ตอนที่/" ซึ่งในที่นี้จะเป็น ดังนั้นผมจึงขอกำหนดให้ "ตอนที่" เป็นพารามิเตอร์อีกตัวหนึ่งของโค้ดด้วย
3) เมื่อคลิ๊กเลือกตอนที่ต้องการอ่านแล้วเราจะเข้าสู่หน้ายืนยันเพื่อเริ่มอ่าน ก็ให้เราคลิ๊กไปที่ "Beginning ชื่อเรื่อง ตอนที่"
4) หน้าเว็บจะโชว์รูป scan หน้าแรกของตอนนั้นๆ ซึ่งสามารถ save รูปสแกนได้โดยการคลิ๊กขวาแล้วเลือก save as เท่านั้น ถ้าจะอ่านหน้าถัดไปเราก็คลื๊กปุ่ม next หรือคลิ๊กไปที่รูปได้เลย ในหน้านี้จะมี drop down box ที่ชื่อว่า "Page" อยู่ด้านบนของรูป scan ด้วยซึ่งมันจะแสดงจำนวนหน้าทั้งหมดภายในตอนนั้นๆ เราจะใช้จำนวนหน้าตัวนี้
ได้เวลาของโค้ด Ruby แล้ว
เราจะทำ 4 ขั้นตอนข้างต้นแบบอัตโนมัติโดยใช้โค้ด ruby และความสามารถของไลบรารี Mechanize จากที่เคยพูดไปใน blog ก่อนหน้านี้เข้าช่วย ซึ่งโค้ดของผมมีหน้าตาแบบนี้ครับ
scrub_onemanga.rb
require 'mechanize'
ROOT_ADDRESS = "http://www.onemanga.com"
def series_exist?(series, address)
# Search for existing series
page = @agent.get(address)
search_form = page.forms.first
search_form.series_name = series
search_result = @agent.submit(search_form)
regex_series = Regexp.new(series)
search_result.links.each do |link|
if link.text =~ regex_series
return true
end
end
return false
end
if ARGV.nil?
puts "please enter Series name and Chapter you need to download."
exit
end
series, chapter = ARGV[0], ARGV[1]
begin
@agent = WWW::Mechanize.new
puts "Searching for #{series} chapter #{chapter}"
unless series_exist?(series, ROOT_ADDRESS) then
puts "#{series} is not found in this site. Try again."
exit
end
puts "Found #{series}!"
puts "Go to first managa page of this chapter"
address = ROOT_ADDRESS + '//' + series + '//' + chapter.to_s + '//'
page = @agent.get(address)
# Now we are at the summaries page before start reading the chapter.
# Then, Click at link 'Begin reading /Series/ /Chapter/'
manga_page = @agent.click( page.links.select { |link| link.text =~ /Begin reading/ }.first )
# Calculate number of page in this chapter by verify 'page' drop-down box
# Walkthrough HTML node using method 'search' which result the Nokogiri's object
p_count = 0
manga_page.search('select#id_page_select.page-select option').each do |ch|
if ch.text =~ /\d{2}/ then p_count += 1 end
end
puts "Chapter##{chapter} has #{p_count} pages"
puts "Starting scrub each page ..."
1.upto(p_count) do |num|
manga_page.search('img.manga-page').each do |img|
puts img['src'] + " is saved"
filename = chapter.to_s + "_" + num.to_s + ".jpg"
@agent.get(img['src']).save_as(filename)
end
next_page_address = ROOT_ADDRESS + manga_page.search('img.manga-page').first.parent['href']
manga_page = @agent.get(next_page_address)
end
puts "DONE !!!\n"
rescue SocketError => e
puts e.to_s
end
จะเห็นว่าโค้ดนี้ต้องการพารามิเตอร์ 2 ตัวด้วยกันซึ่งก็คือ "ชื่อเรื่อง" และ "ตอนที่" ซึ่งค่าทั้งสองจะถูกเก็บอยู่ในตัวแปรที่ชื่อ series และ chapter ตามลำดับ
จากโค้ดข้างตันคุณผู้อ่านจะได้เห็นตัวอย่างของการใช้เมธอดต่างๆ ของอ็อบเจกต์จากคลาส WWW::Mechanize ซึ่งตัวหลักๆที่ใช้ในโค้ดนี้ได้แก่
1) เมธอด get ซึ่งจะรับค่าเป็น url และจะคืนค่าออกมาเป็นอ็อบเจกต์ Page ซึ่งเก็บ content ของเว็บเพจตาม url ที่เราใส่ลงไปทั้งหมด อ็อบเจกต์ Page จึงเปรียบเสมือนหน้าเว็ปจริงๆ ที่เราสามารถที่จะดำเนินการใดๆกับมันต่อไปก็ได้เช่น แสดง link ทั้งหมดที่อยู่ในหน้านั้นด้วยเมธอด links หรือกรอกแบบฟอร์มและ submit เป็นต้น
2) เมธอด click ซึ่งใช้เปลี่ยนหน้าเว็บเพจไปยัง link ที่ต้องการ โดยพารามิเตอร์ของเมธอดนี้จะต้องเป็นอ็อบเจกต์ link นะครับไม่ใช่ url(ลองดูโค้ดบรรทัดที่ 43 อ็อบเจกต์ link นั้นได้มาจากการเรียกใช้เมธอด links ของอ็อบเจกต์ Page อีกที)
3) เมธอด search โดยเมธอดนี้จะทำการค้นหาโหนดที่เราต้องการในหน้าเว็บเพจนั้นๆ ซึ่งโหนดที่เป็นพารามิเตอร์ของเมธอดนี้นั้นเราสามารถใส่มาในรูปของ html node, css node หรือ xpath node ก็ได้ จากโค้ดจะพบค่าของโหนดที่ผมใส่เป็นพารามิเตอร์ให้กับเมธอด search ในบรรทัดที่ 48 นั้นคือ 'select#id_page_select.page-select option' ซึ่งมันคือค่าโหนดของ dropdown box ที่ชื่อ Page นั่นเอง ผมนำค่าโหนดนี้มาจากโปรแกรม firebug ครับ โดยการเข้าไปที่โหมด firebug แล้วใช้เม้าท์จิ้มไปที่ component ที่เราต้องการรู้โหนด ในที่นี้คือ dropdown box จากนั้น ค่าของโหนดจะถูกแสดงขึ้นที่หน้าต่างของโปรแกรม firebug ลองเล่นดูนะครับ... ค่าที่คืนค่าออกมาจากเมธอด search จะเป็นอ็อบเจกต์ของคลาส Nokogiri::XML::Node ครับ ซึ่งสามารถนำไปใช้ประโยชน์ต่อได้อีกมากมายเช่นหาค่าที่เก็บอยู่ใน node นั้นหรือค่าที่อยู่ใน node แม่ ของมัน ฯลฯ อันนี้จะค่อนข้างเวียนหัวนิดนึงต้องค่อยๆทำความเข้าใจไปนะครับ ผมก็ยังงงๆ อยู่เลย
ผลที่ได้หลังจากทดลองรันโค้ด scrub_onemanga.rb จะปรากฏดังรูปด้านล่างนี้ แล้วเราก็จะได้รูป scan ของตอนนั้นๆของการ์ตูนเรื่องที่เราค้นหาครับ
เป็นอย่างไรกันบ้างครับ
หวังว่าคุณผู้อ่านจะได้ไอเดียในการนำ Ruby Mechanize ไปใช้งานหรือต่อยอดกับโปรเจกของคุณได้บ้าง
ใครมีประสบการณ์หรือไอเดียเจ๋งที่อยากจะแชร์กันก็ลอง post เข้ามาพูดคุยกันดูนะครับ
วันจันทร์ที่ 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 ก่อนนะ)
เครื่องมืออีกตัวที่จำเป็นก็คือโปรแกรมแสดงข้อมูล 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 ให้กับโค้ดของเรา
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 ได้อีกด้วย
จากตัวอย่างจะพบว่าชื่อของ input text field ของหน้า google ที่ปรากฎอยู่ในโค้ด HTML นั้นก็คือค่าที่อยู่ใน field name ที่อยู่ใน HTML tag นั้นเอง ซึ่งในที่นี้ค่าของ name จาก tag form จะมีค่าเป็น 'f' ในขณะที่ค่าของ name จาก tag input ที่อยู่ใน form จะมีค่าเป็น 'q'
เราจะนำค่าของ HTML tag ที่ได้มาเขียนโค้ดต่อไป ซึ่งคือขั้นตอนของการป้อนคีย์เวริ์ดที่เราต้องการให้ google ค้นหาแล้วกดปุ่ม "Google Search" โดยสมมติให้คีย์เวิร์ดในการค้นหาคือคำว่า "ruby"
โค้ดของเราจะมีหน้าตาประมาณนี้ครับ
ตัวแปร 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 เท่านั้น
ผลลัพธ์ของการรันโค้ดดังกล่าวจะได้ดังนี้
ซึ่งรายชื่อที่ได้จากผลลัพธ์ของการรันโค้ดนั้นจะตรงกับหน้าแรกของการแสดงผลการค้นหาด้วย google พอดี
คลิ๊ก Link บนหน้า web
เมื่อรู้จักการ submit ฟอร์มแล้วลองมาดูกันต่อว่าถ้าต้องการ click link เพื่อไปยังหน้าต่อไปจะทำยังไง
ง่ายมากครับ งานนี้แค่ใช้เมธอดที่ชื่อว่า click ของอ็อบเจกต์ agent โดยให้ใส่ค่าพารามิเตอร์เป็นอ็อบเจกต์ของ link ที่เราต้องการ click ซึ่ง link ที่ว่านี้จะถูกเก็บเป็นอาเรย์อยู่ในหน้าเว็บเพจซึ่งก็คือตัวแปร search_reault_page ที่เราได้จากตัวอย่างที่แล้ว
ลองดูตัวอย่างของการ click link ที่ชื่อว่า "Next" บนหน้าผลลัพธ์จากการค้นหา ในโค้ดต่อไปนี้ครับ
จะเห็นว่าค่าพารามิเตอร์ที่ต้องใส่ให้กับเมธอด click ในบรรทัดที่ 13 ก็คืออ็อบเจกต์ link ที่ได้จากการใช้ regular expression ไปจับเอา link ที่มีชื่อ(link.text) ว่า "Next" นั้นเอง
ผลลัพธ์จากการรันโค้ดจึงออกมาดังนี้
ลองเล่นดูนะครับ
อ้อ
ท่านใดอยากได้ตัวอย่างมากกว่านี้ ลองเข้าไปที่ web Mechanize ครับ มีตัวอย่างให้ลองทดสอบและศึกษากันพอสมควร ที่หน้า Example และ Guide
ท่านใดเล่นแล้วมีเกิด inspiration (ว่าไปนั่นเลยนะ - -'') หรือลองแล้วติดขัดยังไงก็ลองมาพูดคุยแลกเปลี่ยนความคิดเห็นกันได้นะครับ
ไว้คราวหน้าจะมาต่อถึงวิธีการ scrub ข้อมูลบนหน้าเวปแบบง่ายๆ ครับ
งานนี้เคยบอกไปทีแล้วว่า มันไม่ควรจะใช้คนมานั่ง 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 ได้อีกด้วย
จากตัวอย่างจะพบว่าชื่อของ 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]
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
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 ข้อมูลบนหน้าเวปแบบง่ายๆ ครับ
สมัครสมาชิก:
บทความ (Atom)