ปัจจุบันข้อมูลบนโลกนี้ส่วนใหญ่ล้วนหาได้จากอินเทอร์เน็ต แค่เข้าดูเว็บต่างๆเราก็สามารถโหลดข้อมูลอะไรได้มากมาย
แต่ว่าข้อมูลมีจำนวนมาก การเปิดหน้าเว็บโหลดทีละหน้าหรือทีละไฟล์นั้นย่อมไม่ทันการ ดังนั้นคงจะดีถ้าจะสามารถทำให้งานพวกนี้เป็นไปอย่างอัตโนมัติได้ นั่นคือเขียนโปรแกรมให้มันไปค้นและโหลดข้อมูลจากเว็บต่างๆให้เอง
ไพธอนเป็นภาษาหนึ่งที่นิยมใช้เพื่อเขียนโปรแกรมสำหรับล้วงข้อมูลผ่านอินเทอร์เน็ต เพราะสามารถทำได้ง่าย มีมอดูลเสริมมากมาย
มอดูลในไพธอนที่ใช้ในงานนี้มีมากมาย ในที่นี้จะแนะนำที่ใช้ในเบื้องต้น นั่นคือ requests และ urllib ส่วนตัวที่มาช่วยเสริมอย่างเช่น beautifulsoup จะเขียนแนะนำถึงต่อไป
การเปิดอ่านหน้าเว็บ การอ่านหน้าเว็บที่จริงแล้วก็คล้ายกับการอ่านไฟล์ธรรมดา ปกติถ้าเราจะอ่านไฟล์ธรรมดาเราจะใช้คำสั่ง open ส่วนเวลาที่จะเปิดหน้าเว็บอาจใช้คำสั่ง urlopen
สำหรับในไพธอน 3 จะอยู่ในมอดูลย่อย request ภายในมอดูล urllib
from urllib.request import urlopen
แต่ถ้าเป็นไพธอน 2 จะใช้ต่างกันไป โดย urlopen จะอยู่ใน urllib2 ต้อง import แบบนี้แทน
from urllib2 import urlopen
ตัวอย่างการใช้ ลองอ่านหน้าเว็บ hinaboshi ดู
html = urlopen('https://hinaboshi.com').read()
print(html)
พอแบบนี้ก็จะได้โค้ด html ของเว็บนี้ขึ้นมา
แต่ว่าโค้ดที่ได้เป็นไบนารีซึ่งยังไม่ได้ถอดรหัสเป็นตัวอักษร ถ้าจะให้อ่านได้จำเป็นต้อง decode แล้วระบุชนิด
print(html.decode('utf-8'))
ปกติแล้วหน้าเว็บจะประกอบไปด้วยโค้ด html ซึ่งกำหนดโครงสร้างและรูปแบบการแสดงผลของเว็บทั้งหมด
หากเปิดหน้าเว็บแล้วคลิกขวาตรงที่ว่างแล้วเลือก view source ก็จะสามารถเห็นโค้ดแบบเดียวกันนี้ได้
การล้วงข้อมูลผ่านเว็บนั้นโดยทั่วไปแล้วควรจะต้องมีความรู้ html ไม่มากก็น้อย แต่ในที่นี้จะขอข้ามตรงส่วนนั้นไป เพราะเรื่อง html สามารถหาแหล่งข้อมูลอ่านได้ง่ายมาก
แต่ก็ตั้งใจจะอธิบายพอสังเขปตอนที่เขียนเรื่อง beautifulsoup
ส่วนอีกวิธีหนึ่งในการทำแบบเดียวกันนี้ก็คือใช้มอดูล requests
import requests
requests เป็นมอดูลเสริมที่ไม่ได้มีติดมากับไพธอนแต่แรก แต่การลงก็ทำได้ง่ายด้วย pip install requests
requests สามารถใช้งานได้กว้างขวางและง่ายกว่า urllib จึงแนะนำให้ใช้มากกว่า
การอ่านหน้าเว็บทำโดยใช้คำสั่ง get
r = requests.get('https://hinaboshi.com')
print(r) # ได้
คำสั่ง get จะทำการอ่านเว็บแล้วคืนผลที่ได้ออกมาเป็นออบเจ็กต์ชนิด Response ซึ่งเก็บข้อมูลต่างๆของหน้าเว็บนั้นไว้
ถ้ามาดูที่แอตทริบิวต์ .text จะได้ข้อความเป็น html ที่ถอดรหัสเป็นตัวอักษรออกมา
print(r.text)
เพียงแต่ว่าจะถอดอักษรแบบไหนโปรแกรมจะเดาเอาเอง ซึ่งบางเว็บอาจไม่ได้ถูกถอดอักษรแบบถูกต้อง ถ้าไม่ตรงกับที่ควรเป็นก็จะได้อักษรออกมาเป็นตัวประหลาด
สามารถดูได้ว่าเว็บนี้มีการใช้รหัสอักษรแบบไหนโดยดูที่ .encoding
print(r.encoding) # ได้ utf-8
ในกรณีที่รูปแบบไม่ตรงกับที่ควรจะเป็นก็ให้กำหนดเอนโค้ดที่ถูกต้องลงไปเอง โดยแก้ค่าเขียนทับลงไปใน .encoding เลย (เว็บสมัยนี้ส่วนใหญ่จะเป็น utf-8 กันหมด ถ้าไม่แน่ใจก็เดาเป็น utf-8 ไว้ก่อน)
r.encoding = 'utf-8'
พอทำการแก้ไปแล้ว พออ่าน r.text อีกทีก็จะทำการถอดรหัสแบบนั้น
ส่วนถ้าอยากได้เนื้อหาเป็นไบนารีซึ่งยังไม่มีการถอดรหัสให้ใช้ .content
print(r.content)
r ที่ get ได้ออกมานอกจากเก็บเนื้อหาของเว็บเป็น html ไว้ที่ text แล้วก็ยังเก็บข้อมูลสำคัญอื่นๆเช่น header หรือ cookies ไว้ด้วย สามารถดูได้
print(r.headers)
print(r.cookies)
ในบางเว็บเวลาที่จะเข้าเราต้องเตรียมข้อมูล headers และ cookies เพื่อบ่งบอกว่าเราเข้าเว็บผ่านอะไรและล็อกอินด้วยผู้ใช้คนไหนก็สามารถเสริมข้อมูลส่วนนี้ลงไปตอนที่ get ได้
นอกจาก get แล้วก็ยังมี post, patch, delete แต่เรื่องเหล่านี้เป็นระดับสูงขึ้นไป ในที่นี้ขอเน้นการดึงข้อมูลจากเว็บทั่วไปที่แค่เปิดหน้าเว็บขึ้นมาธรรมดาก็สามารถดูข้อมูลได้ทันที
การดาวน์โหลดไฟล์ มีอยู่หลากหลายวิธีด้วยกันในการโหลดไฟล์จากเว็บลงมาในเครื่องเรา
1. open ไฟล์แล้วเขียน เมื่ออ่านหน้าเว็บโดยใช้ urllib หรือ requests แล้วดึงเนื้อหาออกมาได้ ก็สามารถนำมาบันทึกลงเครื่องได้โดยการเปิดไฟล์แล้วเขียนใส่ไฟล์ (เกี่ยวกับการเขียนไฟล์
https://phyblas.hinaboshi.com/tsuchinoko18)
ปกติเวลาโหลดไฟล์จะอ่านเป็นแบบไบนารี คือ r.content แล้วเขียนไฟล์ในโหมด wb
r = requests.get('https://hinaboshi.com')
with open('hinaboshi.html','wb') as f:
f.write(r.content)
ก็จะได้หน้าเว็บแรกมาเก็บไว้ในเครื่อง เพียงแต่ว่าการแสดงผลก็จะแปลกเพราะมาแต่ html เปล่าๆ ไม่ได้มีการเซฟส่วนประกอบที่เกี่ยวข้องเช่นพวก css หรือ javascript รวมถึงไม่มีรูปด้วย
พวกไฟล์ไบนารีเช่นรูปภาพหรือวีดีโอก็สามารถโหลดได้ด้วยวิธีเดียวกันนี้ เช่นลองใช้กับไฟล์รูปภาพดู
url_file = 'https://hinaboshi.com/rup/rupprakopwalidet/1460321927319907.jpg'
chue_file = 'tapris.jpg'
r = requests.get(url_file)
with open(chue_file,'wb') as f:
f.write(r.content)
เท่านี้รูปก็จะถูกโหลดมาลงเครื่อง
2. ใช้ urlretrieve ใน urllib มีคำสั่งที่สะดวกที่ใช้โหลดไฟล์ได้ทันทีอยู่แล้ว คือ urlretrieve
from urllib.request import urlretrieve # สำหรับไพธอน 3
# from urllib import urlretrieve # สำหรับไพธอน 2
urlretrieve(url_file,chue_file)
3. โหลดเป็นก้อนๆ กรณีที่ไฟล์มีขนาดใหญ่มากการโหลดรวดเดียวเลยจะกิน RAM มาก การโหลดเป็นก้อนๆจะช่วยประหยัด RAM ทำให้อาจมีประสิทธิภาพมากกว่า
ทำได้โดย
r = requests.get(url_file,stream=True)
with open(chue_file,'wb') as f:
for c in r.iter_content(chunk_size=1024):
f.write(c)
stream=True จะทำให้ข้อมูลค่อยๆถูกอ่าน ไม่ได้อ่านทั้งหมดแต่แรกในทีเดียว
iter_content เป็นการสร้างอิเทอเรเตอร์ที่ไล่อ่านข้อมูลมาทีละนิด โดย chunk_size คือขนาดของไฟล์ที่โหลดแต่ละครั้ง หน่วยเป็นไบต์ ในที่นี้ 1024 คือ 1 kb
4. เรียกใช้โปรแกรมช่วยโหลด สามารถเรียกคำสั่งในเชลเพื่อให้โหลดได้ เช่น โปรแกรมช่วยโหลดที่ใช้บ่อยๆเช่น curl wget aria2c
aria2c เป็นโปรแกรมโหลดที่สามารถทำการโหลดแยกส่วนแบบคู่ขนานได้โดยอัตโนมัติ ทำให้การโหลดเร็วมาก
>>
https://aria2.github.io ในที่นี้จะยกตัวอย่างการใช้ aria2c ส่วน curl wget ก็ใช้ได้ในลักษณะเดียวกัน สามารถสั่งได้โดยใช้คำสั่ง os.system หรือ subprocess.call
cmd = 'aria2c -x5 -o %s %s'%(chue_file,url_file)
import os
os.system(cmd)
หรือ
import subprocess
subprocess.call(cmd,shell=1)
ด้วยวิธีการต่างๆเหล่านี้ขอเพียงรู้ url ของแต่ละหน้าเว็บหรือรูปภาพ ก็สามารถเขียนโปรแกรมให้วนซ้ำเพื่อโหลดทุกสิ่งที่ต้องการได้โดยอัตโนมัติ
โหลดไฟล์ด้วย multiprocessing ถ้าเรามีไฟล์ที่ต้องการจำนวนมาก การโหลดพร้อมกันหลายๆไฟล์จะเร็วกว่าการโหลดไปทีละไฟล์
ดังนั้นกรณีแบบนี้อาจลองใช้ multiprocessing รายละเอียดเรื่องนี้อธิบายไว้แล้วใน
https://phyblas.hinaboshi.com/20180317 ตัวอย่างการทำ
import multiprocessing as mp
def dOwNlOaD(id_phap):
chue_file = '%d.jpg'%id_phap
url_file = 'https://hinaboshi.com/rup/rupprakopwalidet/'+chue_file
urlretrieve(url_file,chue_file)
if(__name__=='__main__'):
for id_phap in [1055235151161922,1233843746634394,1460321927319907]:
p = mp.Process(target=dOwNlOaD,args=(id_phap,))
p.start()
แบบนี้ก็จะได้ไฟล์ภาพมา ๓ ภาพ โดยแต่ละภาพถูกโหลดพร้อมๆกัน
หรือถ้าจะใช้ Pool แล้ว map เอาก็อาจยิ่งเขียนง่าย
if(__name__=='__main__'):
p = mp.Pool(processes=3)
p.map(dOwNlOaD,(1055235151161922,1233843746634394,1460321927319907))
ทั้งหมดนี้เป็นวิธีการดึงข้อมูลจากเว็บ แต่ว่าข้อมูลจากหน้าเว็บที่เป็น html นั้นจะนำมาใช้ก็ต้องทำการสกัดข้อมูลอีกที ตอนต่อไปจะแนะนำการสกัดข้อมูลวิธีหนึ่งที่นิยมใช้กันก็คือ beautifulsoup
>>
https://phyblas.hinaboshi.com/20180323สุดท้ายนี้อยากบอกว่าการใช้โปรแกรมเพื่อล้วงข้อมูลในเว็บเป็นการสร้างภาระให้กับเว็บนั้นเป็นอย่างมาก ควรจะเพลาๆ ไม่ควรทำเกินความจำเป็น
อ้างอิง