TL;DR

ใครบอกว่า Bot เป็นเรื่องยาก? เรื่องยากความจริงแล้วก็แค่เพราะเราไม่รู้ /me เขียนบทความนี้ เพื่อให้ทุกคนลอง แล้วจะพบว่าการเขียน Bot เป็นเรื่องง่ายกว่าที่คิด

#ภาษาอังกฤษวันละคำ วันนี้ ภูมิใจเสนอคำว่า “SPIDER” ออกเสียงว่า สะ-ไป-เด้อ แปลว่า “แมงมุม” #อีกรอบนะฮะ “SPIDER” แปลว่า “แมงมุม”

แต่สำหรับหลายๆคน คงเข้าใจต่างออกไป #แล้วมันคืออะไร

จริงๆแล้ว WebBOT, SPIDER, CLAWER ในมุมมองของบางคน ไม่ใช่อะไรที่เกินไปกว่า โปรแกรมคอมพิวเตอร์ ที่ไล่เปิดเปิดเวปไซท์ขึ้นมา เพื่อเก็บรวบรวมข้อมูลต่างๆ จากนั้น ก็ ไต่ต่อจากลิงค์อยู่ในเวปไซท์ที่เปิดนั้น ไปเรื่อยๆ ไม่เหนื่อย #ก็มันเป็นแค่โปรแกรมหนิ #แต่ควรมีดีเลย์นะ

ตัวอย่างดังๆ ก็อย่างเช่น Googlebot , Bingbot ที่คอยรวบรวมเวปไว้สำหรับ #search ที่เราใช้ๆกันทุกวัน #กูเกิลพังไปฉันคงมีชีวิตอยู่ไม่ได้

ซึ่งการจะสร้างมันขึ้นมาก็ไม่ได้ยากอย่างที่คิด ลองมาดูกัน

Requirements

Python

//already installed in Ubuntu

Pip

wget https://bootstrap.pypa.io/get-pip.py;

sudo python get-pip.py;

Requests

sudo pip install requests

Beautiful Soup

sudo pip install beautifulsoup4

Basic Principle

ก่อนที่จะทำแบบนี้ ก่อนอื่น ต้องมาทำความเข้าใจ การทำงานของ Website กันก่อน website ที่เราเล่นๆทุกวันนี้ ส่วนใหญ่สื่อสารในรูปแบบที่ชื่อว่า HTTP ซึ่งเป็นรูปแบบที่คอมใช้ในการสื่อสารกัน #เหมือนกับภาษา เช่น ถ้าเป็นคนไทยคุยกัน ก็จะสื่อสารกันด้วยรูปแบบที่ชื่อว่า THAI

แต่ หลักการของ HTTP แต่ต่างจากภาษาทั่วๆไป คือ มันแบ่งคอมเป็น 2 ประเภท คือ #client และ #server ซึ่ง website จะอยู่ในเครื่อง server ส่วน web browser เช่นพวก #Chrome #Safari #InternetExplorer จะเป็น client

ซึ่งเมื่อใส่ URL ที่ต้องการเข้าไปไป client จะไปถาม server ว่าเวปไซท์นี้มีเนื้อหายังไง ซึ่ง server ก็จะตอบเป็น HTML code #พร้อมรายละเอียดอื่นๆด้วย

#ตัวอย่าง HTML


<html>
<head> </head>
<body> </body>
</html>

หลังจากนั้น #WebBrowser จะมีหน้าที่ แปลความ HTML #มาแสดงเป็นภาพสวยๆ ด้วยสิ่งที่เรียกว่า “Render Engine” ดังนั้น แต่ละ browser อาจจะแปลไม่เหมือนกันก็ได้ โดยเฉพาะ #InternetExplorer ที่มีปัญหาบ่อยๆ เพราะว่า ไม่ยอมแปลตามมาตรฐาน ทำให้บางเวปเปิดที่ brower อื่นแล้วสวย พอเปิดใน #InternetExplorer แล้วเน่า

ซึ่ง #SPIDER ของเราก็จะทำในลักษณะที่คล้ายๆกัน คือ

  1. ส่ง HTTP ถามไปยัง url เป้าหมาย
  2. แปลความ HTML ที่ได้รับ

Let’s Start

ส่ง HTTP ถามไปยัง URL เป้าหมาย

เริ่มต้นด้วยการส่งไปถามข้อมูลจากหน้าเวปธรรมดาที่ไม่ต้องการ login อย่าง google.com สามารถทำได้ง่ายๆเพียง

import requests
r = requests.get('https://www.google.com')
print r.text

หาทุกอย่างเป็นไปได้ด้วยดี ก็จะเห็น HTML code เต็มไปหมดเลย~

แต่ #ในชีวิตจริงไม่ได้ง่ายแบบนั้น หลายๆเวปที่จำเป็นต้องกรอก username/password หรือ form รูปแบบต่างๆ #แล้วฉันจะทำยังไง? #แต่มันก็ไม่ได้ยากอย่างที่คิดหรอกนะ

ซึ่งเราจะใช้ Chrome เป็นเครื่องมือในการแกะรอยครั้งนี้ #ตามวิธีต่อไปนี้

  • เปิด chrome แล้วพิมเวปที่เราจะ login
  • กด ctrl+shift+J เพื่อ เปิด console ขึ้นมา
  • กดเลือก tab Network
  • ลองกรอกฟอร์มแล้วส่ง ข้อมูล มั่วๆ จะเห็นว่า มันเกิดการส่งข้อมูล จากนั้นหาก้อนที่เป็นข้อมูลที่กรอกไป
  • หากกดเข้าไปดูก็จะได้ข้อมูลครบทุกอย่างที่เราต้องการ ซึ่งจะประกอบด้วย

    • Url ที่เป้าหมายสำหรับการ login
    • ชนิดของคำถามที่จะส่งไปหา server มักจะเจอเพียง GET [ใช้ requests.get], POST [ใช้ requests.post]
    • ข้อมูลที่ต้องส่งไปเพื่อ login
  • ลุยโค้ดกันเลย
import requests
with requests.Session() as session:
    payload = {"member%5Bemail%5D": "....", 
               "member%5Bcrypted_password%5D": "...",
               "persistent%5Bremember%5D": "1",
               "action": "login",
               "redirect":"Lw%3D%3D"}
    r = session.post("http://pantip.com/login/authentication", data=payload)
    print r.text
  • สังเกตุได้ว่า โค้ดค่อยข้างเปลี่ยนไปมาก #เพราะอะไร? สิ่งที่สำคัญที่มาพร้อมกับการ login นอกจาก การส่งข้อมูลแล้ว มันก็คือ การบอกให้ระบบรู้ว่า เรายังคงอยู่ในฐานะที่ login อยู่ #ฉันยังไม่ได้ออกจากระบบ ซึ่งนั้นจำเป็นจะต้องมีการเก็บ Session ซึ่งเก็บสถาณะให้ระบบสามารถตรวจสอบได้

สำหรับใครที่สนใจ Requests ท่ายากกว่านี้ คลิ๊ก ศึกษา Requests เพิ่มเติม

แปลความ HTML ที่ได้รับ

หลังจากที่ผ่านความยากลำบากเพื่อให้ได้ HTML จาก server แล้ว #งานต่อมา คือ การแปลความหมายของ HTML #ควรจะเริ่มยังไงดี

พูดถึงมาตั้งนานละ HTML HTML HTML แล้ว ไอ้ HTML #คืออะไร?

HTML เป็น #MarkupLanguage ซึ่งหมายถึง ภาษาสำหรับการแสดงผลโดยไม่มีการคำนวนเข้ามาเกี่ยวข้อง ดังนั้นจึงเป็นไปไม่ได้ที่จะมีใครมาบอกว่า ผมเขียนโปรแกรม #เครื่องคิดเลข ด้วยHTML สิ่งที่ทำให้เวปเกิดการ movement คือส่วนที่เป็น #javascript, #coffeescript, #dart … ต่างหาก

โครงสร้าง HTML เป็นโครงสร้างที่อยู่ในรูปแบบที่เรียกว่า #tree

โดยสิ่งที่อยู่ใน <> จะเรียกว่า #tag เช่น <html> , <body> , <p> , แต่ละ #tag ต้องมี tag เปิด และ tag ปิด แต่ อาจจะไม่มี tag ปิดบ้าง #นิสหน่อย ซึ่งเกิดจาก ความขี้เกียจทาง #ประวัติศาสตร์อันยาวนาน ของ HTML นอกจากนี้ ก็คือ สิ่งที่เป็นส่วนขยายเรียกว่า #attribute เช่น

<a href="www.google.com"> ... </a>

#href เป็น attributeของ tag <a> โดย attr href มีค่า = "www.google.com"

หลักจากเข้าใจแล้วว่า #HTML คืออะไร แต่จะรู้ได้อย่างไรว่า จุดที่เราสนใจ คือ tag อะไร #เข้าประเด็น

เราจะยังคงสามารถใช้ Chrome เป็นเครื่องมือในการแกะรอยได้เช่นเดียวกัน #หนิมันไว้เปิดเวปหรือไว้แฮ๊กวะ

  • ให้ click ขวาในส่วนที่เราสนใจ เลือกหัวข้อ Inspect Element
  • เลือก tag ให้ตรงตามที่ต้องการ โดยดูจากแรงเงา #สีน้ำเงิน
  • ศึกษารูปแบบโค้ดจาก console ที่ขึ้นมา

เมื่อรู้แล้วว่า ส่วนที่สนใจคือ tag อะไร ก็เริ่ม ใช้ #BeautifulSoup กันได้เลยยย ซึ่ง BeautifulSoup เป็น library ที่ใช้ในการแปลความ HTML ให้ออกมาอยู่ในรูปแบบ tree ซึ่งสามารการใช้ค้นหา tag ที่ต้องการ โดย

body = soup.findAll("body")  

ซึ่งจะได้มาเป็น list ตัวแทนของ tag <body> และ สามารถดึง ข้อความใน tag หรือ attribute ได้โดย

body = soup.findAll("body")  

print body[0].text  <span class="tag-en">     #แสดงค่าข้อมูลที่อยู่ภายใน</span> tag
print body[0][class"] <span class="tag-en">  #แสดงค่า</span> attribute class ของ tag 

่ศึกษา BeautifulSoup เพิ่มเติม ซึ่งเมื่อนำมาประกอบกับโค้ดเดิมจะได้

import requests
from bs4 import BeautifulSoup
with requests.Session() as session:
    payload = {"member%5Bemail%5D": "....", 
               "member%5Bcrypted_password%5D": "...",
               "persistent%5Bremember%5D": "1",
               "action": "login",
               "redirect":"Lw%3D%3D"}
    r = session.post("http://pantip.com/login/authentication", data=payload)
    r = session.get("http://pantip.com/tag/ชีวิตวัยรุ่น")
    soup = BeautifulSoup(r.text)
    tag_a = soup.findAll('a')
    for tag in tag_a:
        print tag["href"]

หากทุกอย่างเป็นไปอย่างถูกต้อง #มันจะไม่บั๊คนะ เราจะได้ลิงค์ทั้งหมดปรากฏ #เย้ #จบซะที

… END …

แต่อย่างไรก็ตามทั้งหมดนี้ ก็เป็นเพียง #Basic เบื้องต้นของการทำ #SPIDER ในฉบับสมบูรณ์ยังมีอีกหลายส่วนที่ต้องศึกษา เช่น การทำให้โปรแกรมสามารถไต่ไปยังลิงค์ต่อไปได้อย่างต่อเนื่อง #เพิ่มอีกนิสเดียว, การคัดกรองลิงค์, การป้องกันไม่ให้เจอลิงค์กับดัก #คืออะไรหว่า #ไม่บอกหรอก และอีกมากมาย~

สุดท้ายนี้ ขอฝากคำพูดนึงไว้

ความรู้สามารถใช้ได้ในทางที่ดี และ ทางที่ไม่ดี #แยกให้ออกว่าอะไรคือสิ่งที่ควร แล้วจะได้ไม่ต้องกังวลกับผลลัพย์จากสิ่งที่ทำ :))

ปล. ขออนุญาต และขอขอบคุณ Pantip.com ที่เป็นตัวอย่างในครั้งนี้

Credit