φυβλαςのβλογ
บล็อกของ phyblas



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

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

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

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

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



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

  ค้นหาบทความ

  บทความแนะนำ

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

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文