เขียน Python เพื่อเป็น crawler และช่วย download file
อยากได้เพลงเสียงเรียกเข้าใหม่นะครับ เลยลองหาๆดู ว่ามีเสียงไหนน่าสนใจบ้าง ไปเจอเข้ากับเว็บรวมเสียงเพลงในเกม patapon เข้าพอดี มีตัวอย่างให้ฟังและ ดาวน์โหลดได้เลย…
อยากได้เพลงเสียงเรียกเข้าใหม่นะครับ เลยลองหาๆดู ว่ามีเสียงไหนน่าสนใจบ้าง ไปเจอเข้ากับเว็บรวมเสียงเพลงในเกม patapon เข้าพอดี มีตัวอย่างให้ฟังและ ดาวน์โหลดได้เลย แต่มีปัญญหาตรงที่มันจะต้องกดลิงค์เพื่อเข้าไปฟังทีละเสียง และตอนดาวน์โหลดก็ต้องไปหน้าฟังเสียงก่อนถึงจะกดปุ่มดาวน์โหลดได้
เลยเขียนโปรแกรมง่ายๆเพื่อช่วยในการดาวน์โหลดขึ้นมาครับ
อันดับแรกเลย package ที่ใช้ นอกจากตัว library มาตรฐานจะมีอยู่สองอันคือ request กับ BeautifulSoup4 ติดตั้งโดยใช้คำสั่ง
pip install request
pip install beautifulsoup4
การทำงานจะแยกเป็น 3 ส่วนคือ
เปิดหน้า url เพื่อหาลิงค์
ใช้ request ในการ เรียกข้อมุลจากหน้านั้นมาดู
import requests
try:
req = requests.get(url)
except requests.exceptions.ConnectionError as e:
print e, "... Retry"
ในส่วนของ exception ที่เป็น ConnectionError นั้นจะเกิดในกรณีที่ อยู่ๆมันเรียกไปแล้วไม่ได้ หรือได้ข้อมูลที่ดูไม่ make sense กลับมา ซึ่งกรณีนี้ผมให้มันทำการ retry ได้ เลยใส่ exception ไว้ ตอนนี้เราก็จะได้ ข้อมูลหน้า page ทั้งหน้ามาอยู่ในตัวแปร req แล้ว
จากนั้นก็ทำการเช็คว่า หน้าที่เรียกเมื่อกี้ ได้ status code เป็น 200 (success) หรือไม่ ถ้าไม่ใช่ก็ไม่ต้องทำงานต่อ
if(req.status_code != 200):
return []
ถึงตรงนี้ เมื่อเราเรียก req.text ก็จะได้ html ของหน้าเว็บทั้งหน้าแล้ว ในส่วนต่อไป เราจะทำการ หาลิงค์ที่เราจะทำการ ดาวน์โหลด
Scan หาลิงค์ที่จะดาวน์โหลด
ในส่วนนี้เพื่อให้ง่าย ผมใช้ BeautifulSoup เข้ามาช่วย ใครไม่เคยใช้ก็สามารถดู วิธีใช้ใน Doc เลยครับ มีตัวอย่างและการใช้งานอย่างละเอียด ดูแล้วมี code ให้ลองทำตามง่ายๆ ด้วย
สิ่งที่เราจะทำคือ อันดับแรกให้ BS (BeautifulSoup) ทำ parser กับข้อมูลใน req.text ทั้งหมดก่อน จากนั้น หา link ที่มี string ที่เราต้องการ อย่างในกรณีนี้คือเราจะหาลิงค์ที่มีข้อความว่า download ซึ่งจะหน้าตาแบบนี้ <a href="...">Download</a> แล้วจากนั้นเอาค่าที่อยู่ใน href ทั้งหมด มาทำเป็น list ไว้ จะได้คำสั่งดังนี้
soup = BeautifulSoup(req.text, 'html.parser')
linklist = [l.get('href') for l in soup.find_all("a", string="Download")]
และเนื่องจาก หน้าเว็บนี้ จะมีหน้ารวมลิงค์ก่อน แต่ปุ่มดาวน์โหลดจะยังไม่สามารถดาวน์โหลดได้เลย แต่ว่าจะต้องกดเข้าไปเพื่อเปิดอีกหน้าหนึ่งก่อน จึงจะมีปุ่มดาวน์โหลดที่ได้ไฟล์จริงๆ อยู่ในหน้านั้น ลิงค์ที่ได้ในตอนแรกนั้น จึงต้องนำมาทำการเรียกเปิดและหาลิงค์สำหรับไฟล์อีกรอบก่อน จึงจะใช้ได้ เราจึงเขียน function ขึ้นมีอันนึงสำหรับ หาลิงค์ดาวน์โหลดนะครับ ชื่อ getdownload
# @url : url of target page
# @a_string : a string in [<a>a_string</a>] to filter link
# return : list of link url
def getdownload(url,a_string):
# try to open url and retry if connection error
try:
req = requests.get(url)
except requests.exceptions.ConnectionError as e: # This is the correct syntax
print e, "... Retry"
return getdownload(url,a_string)
# check response status
if(req.status_code != 200):
return
# get page content
soup = BeautifulSoup(req.text, 'html.parser')
# capture all download link
linklist = [l.get('href') for l in soup.find_all("a", string=a_string)]
print "Get {} download links".format(len(linklist))
# return all download link
return linklist
เมื่อเรามีคำสั่งสำหรับการหาลิงค์ดาวน์โหลดแล้ว สิ่งที่ต้องทำคือนำ ลิงค์ที่ได้จากหน้าหลักมาวน for เพื่อเรียกคำสั่ง getdownload นี้สำหรับทุกลิงค์
for link in link_list:
print "#### Link {}".format(link)
download_list = getdownload(link,a_download_string)
ตอนนี้เราจะได้ชุดคำสั่งที่เข้าถึง url จริง ๆที่มีไฟล์อยู่แล้ว ขั้นต่อไปคือการ ดาวน์โหลดไฟล์มาลงที่เครื่อง
ดาวน์โหลดไฟล์ด้วย python
python จะมีคำสั่งสำเร็จรูปในการดาวน์โหลดจาก url ไปลงไฟล์ให้อยู่แล้ว นั่นคือคำสั่ง urllib.urlretrieve เพียงแค่ใส่ url และชื่อที่ต้องการให้เซฟลงเครื่อง ก็เสร็จเลย เช่น
import os
path = "G:\download" # path ที่จะ save file wx]'
filename = url.split('/')[-1] # เอาชื่อ file จากใน url
full_filename = os.path.join(path,filename)
# เริ่ม download
urllib.urlretrieve(url, full_filename)
คำสั่งจะทำการดาวน์โหลดและเขียนลงไฟล์จนเสร็จก่อน จึงจำทำงานต่อ เพราะฉะนั้นคำสั่งข้างต้นจะเป็นการทำงานแบบ 1 thread เท่านั้น ถ้าใช้ในการวน for ก็จะยังไม่ทำงานต่อจนกว่าจะ download เสร็จ
ตัวอย่าง code สมบูรณ์
สุดท้ายก็นำทุกอย่างมารวมกัน เพื่อให้ได้โปรแกรม ค้นหาและดาวน์โหลด (เขียนละทดสอบใน python2.7) View the Gist