φυβλαςのβλογ
phyblas的博客



การใช้ python ล้วงข้อมูลจากเว็บ (ใช้ requests หรือ urllib)
เขียนเมื่อ 2018/03/20 10:42
ปัจจุบันข้อมูลบนโลกนี้ส่วนใหญ่ล้วนหาได้จากอินเทอร์เน็ต แค่เข้าดูเว็บต่างๆเราก็สามารถโหลดข้อมูลอะไรได้มากมาย

แต่ว่าข้อมูลมีจำนวนมาก การเปิดหน้าเว็บโหลดทีละหน้าหรือทีละไฟล์นั้นย่อมไม่ทันการ ดังนั้นคงจะดีถ้าจะสามารถทำให้งานพวกนี้เป็นไปอย่างอัตโนมัติได้ นั่นคือเขียนโปรแกรมให้มันไปค้นและโหลดข้อมูลจากเว็บต่างๆให้เอง

ไพธอนเป็นภาษาหนึ่งที่นิยมใช้เพื่อเขียนโปรแกรมสำหรับล้วงข้อมูลผ่านอินเทอร์เน็ต เพราะสามารถทำได้ง่าย มีมอดูลเสริมมากมาย

มอดูลในไพธอนที่ใช้ในงานนี้มีมากมาย ในที่นี้จะแนะนำที่ใช้ในเบื้องต้น นั่นคือ 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

สุดท้ายนี้อยากบอกว่าการใช้โปรแกรมเพื่อล้วงข้อมูลในเว็บเป็นการสร้างภาระให้กับเว็บนั้นเป็นอย่างมาก ควรจะเพลาๆ ไม่ควรทำเกินความจำเป็น



อ้างอิง


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

目录

从日本来的名言
python
-- numpy
-- matplotlib

-- pandas
-- pytorch
maya
机器学习
-- โครงข่าย
     ประสาทเทียม
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

เรียนรู้วิธีการใช้ regular expression (regex)
หลักการเขียนทับศัพท์ภาษาจีนกวางตุ้ง
การใช้ unix shell เบื้องต้น ใน linux และ mac
หลักการเขียนทับศัพท์ภาษาจีนกลาง
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
บันทึกการเที่ยวสวีเดน 1-12 พ.ค. 2014
แนะนำองค์การวิจัยและพัฒนาการสำรวจอวกาศญี่ปุ่น (JAXA)
เล่าประสบการณ์ค่ายอบรมวิชาการทางดาราศาสตร์โดยโซวเคนได 10 - 16 พ.ย. 2013
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
บันทึกการเที่ยวญี่ปุ่นครั้งแรกในชีวิต - ทุกอย่างเริ่มต้นที่สนามบินนานาชาติคันไซ
หลักการเขียนทับศัพท์ภาษาญี่ปุ่น
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ
ทำไมถึงอยากมาเรียนต่อนอก
เหตุผลอะไรที่ต้องใช้ภาษาวิบัติ?