試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

2DbookloaderからフリーアップロードファイルをダウンロードするPythonスクリプト

皆様へのお知らせ

2014/03/08現在、このスクリプトは正しく動作しません。記事を執筆した当時は動いていたのですが、2Dbookloaderの仕様が変わったため、正しく動作しなくなったと考えられます。


昨日に続き、Pythonスクリプトを書きました。2Dbookloader(URL : http://2dbook.com)から鍵のないフリーアップロードファイルをダウンロードするためのスクリプトです。スクリプト実行のためには、PythonおよびXMLパーサであるBeautiful Soupがインストールされている必要があります。



いつもの通り、基本的にはLinux用のスクリプトです。また、sudoコマンドあるいはroot権限で実行するようにして下さい。多くのHTMLやアップロードファイルをダウンロードするため、これらのダウンロード時に間隔を挟んで、サーバに極端に負荷をかける事の無いようにしてあります。



ファイル一覧ページのURLがやや不規則になっているため、スクリプト中でURLをリストとしてまとめて定義しています。スクリプトソースコードを見た人の中には「おや?」と思う方もいるかもしれませんが、問題ありません。



スクリプト使用前に以下の準備が必要になります。



CentOS(Redhat系)の場合

#!/bin/sh
#
# sudoまたはroot権限で実行すること
#

# パッケージインストール
yum -y install python-setuptools

# setuptools 0.8
wget https://bitbucket.org/pypa/setuptools/raw/0.8/ez_setup.py
python ez_setup.py --user

# pip
easy_install pip
pip install beautifulsoup

Ubuntu(Debian系)の場合

#!/bin/bash
#
# sudoまたはroot権限で実行すること
#

# パッケージインストール
# setuptools 0.8
wget https://bitbucket.org/pypa/setuptools/raw/0.8/ez_setup.py
python ez_setup.py --user

# pip
easy_install pip
pip install beautifulsoup


スクリプトソースコードは以下の通りです。


#!/usr/bin/python
#-*- coding:utf-8 -*-
#
# 2Dbookloaderからフリーアップロードファイルを取得するスクリプト
#

# パッケージのインポート
import os
import sys
import re
import urllib
import urllib2
import StringIO
import gzip
import time
from datetime import datetime
from BeautifulSoup import BeautifulStoneSoup
from HTMLParser import HTMLParser


# 関数定義
# HTMLタグを取り除くクラスと関数
class MLStripper(HTMLParser):
	def __init__(self):
		self.reset()
		self.fed = []
	def handle_data(self, d):
		self.fed.append(d)
	def get_data(self):
		return ''.join(self.fed)

def strip_tags(html):
	s = MLStripper()
	s.feed(html)
	return s.get_data()



# 指定したURLのHTMLページの内容をダウンロードする関数
def html_download(html_url):

	# ダウンロード間隔を開けるため、一時停止
	time.sleep(2)		# 2秒間一時停止する

	# 例外処理
	# HTMLページを取得しリストに格納
	# 失敗時にはエラーメッセージのみ返す
	try:
		# HTTPリクエスト
		req = urllib2.Request(html_url, headers={'User-Agent' : 'Magic Browser', 'Accept-encoding' : 'gzip'})
		con = urllib2.urlopen(req)
		html = con.read()
		
		# body部分がgzip化されている場合の処理
		if con.info().get('Content-Encoding') == 'gzip':
			data = StringIO.StringIO(html)
			gzipper = gzip.GzipFile(fileobj=data)
			html = gzipper.read()

	except urllib2.URLError, e:
		sys.exit("Error! : URLエラーにより画像を取得できません")
	except urllib2.HTTPError, e:
		sys.exit("Error! : HTTPエラーにより画像を取得できません")

	# 戻り値
	return html

	

# 2Dbookloaderからzipファイルをダウンロードする関数
def zip_2dbook_download(dl_path, file_name):

	# ダウンロード間隔を開けるため、一時停止
	time.sleep(5)		# 5秒間一時停止する

	# 変数
	output   = "" 		# 出力ファイル名
	file_url = ""		# ファイルのURL

	# 正規表現
	pat_output = re.compile('.+/(.*)$')

	# URL指定
	urls = [
		"http://199.189.108.116/file/%s.zip"%(file_name),
		"http://173.45.36.44/file/%s.zip"%(file_name),
		"http://67.208.80.59/file/%s.zip"%(file_name),
		"http://199.189.108.116/file/%s.rar"%(file_name),
		"http://173.45.36.44/file/%s.rar"%(file_name),
		"http://67.208.80.59/file/%s.rar"%(file_name),
	]

	# ページの存在を確認
	for i in urls:
		ret = urllib.urlopen(i)
		if ret.getcode() == 200:
			file_url = i
			m = pat_output.match(i)
			if m is not None:
				output = "%s/%s"%(dl_path, m.group(1))
				print output		# ファイルの出力先を表示する
			break

	# 一致したものがなければ終了する
	if file_url == "":
		print "ファイルが見つかりませんでした"
		return

	# URLよりファイルを取得する
	# もし同名のzipファイルが存在するならば、上書きは行わない
	if not os.path.exists(output):
		urllib.urlretrieve(file_url, output)

	# 戻り値
	return
	


# main関数
if __name__ == '__main__':

	# 変数
	dl_path     = "./downloads"		# ファイルのダウンロード先ディレクトリ
	count       = 0				# ダウンロードしたファイル数
	count_limit = 100			# ダウンロードするファイルの数の上限
	start_page  = 1				# ダウンロードを開始するページ番号
	info        = []			# HTMLから抽出した文字列を格納するリスト

	# 各ページのURLのリスト
	page_urls = [
		"http://2dbook.com/lists/search/word:/free:0",
		"http://2dbook.com/lists/search/word:/free:1",
		"http://2dbook.com/lists/search/word:/free:1/period:/sorting:/page:2"
	]
	for i in range(3, 100):
		page_urls.append("http://2dbook.com/lists/search/page:%d/word:/free:1/period:/sorting:"%(i))

	# 正規表現
	pat_file = re.compile('<p class="filetitle"><a href="(.*?)">(.*?)</a></p>')		# 検索結果のページからファイルページのURLを抜き出す

	# メッセージの出力
	print "ダウンロードを開始しました..."

	# ディレクトリを作成し、権限を付与する
	if not os.path.exists(dl_path):
		os.mkdir(dl_path)
	os.chmod(dl_path, 0777)


	# URLを含むリストを作成
	for i in range(start_page, (count_limit/40+start_page+2)):
		# URL
		html_url = page_urls[i]

		# 検索結果ページのHTMLを取得
		html = html_download(html_url)

		# HTMLから情報を取り出す
		soup = BeautifulStoneSoup(html)
		tmp_list = soup.findAll("p", {"class": "filetitle"})	# 一時的なリスト
		info = info + tmp_list					# リストの結合


	# 重複要素を除去したリストを得る
	info = list(set(info))

	# リストからURLを取得
	for i in info:
		# ダウンロードしたファイル数が上限に達した場合は終了
		if count > count_limit:
			break;
		else:
			count += 1

		# ファイルページのURLを取得
		m1 = pat_file.match(str(i))		# 文字列へと変換後、マッチング
		link = m1.group(1)
		file_page_url = "http://2dbook.com%s"%(link)

		# ファイルページURL先のHTMLファイルの内容を取得
		file_page_html = html_download(file_page_url)

		# HTMLからファイル名を判別する
		file_page_soup     = BeautifulStoneSoup(file_page_html)
		file_page_titlebar = file_page_soup.findAll("div", {"class": "titlebar"})
		tmp = str(file_page_titlebar[0]).replace('\n','')	# 文字列へと変換し、改行文字を削除
		file_name = strip_tags(tmp)

		# ファイルのダウンロード
		zip_2dbook_download(dl_path, file_name)


	# メッセージの出力
	print "Success! : ダウンロードが完了しました"


スクリプトの作成に当たり、以下のサイトを参考にしました。


Strip HTML from strings in Python - Stack Overflow

In Python, how do I use urllib to see if a website is 404 or 200? - Stack Overflow

python - Beautiful Soup and extracting a div and its contents by ID - Stack Overflow

とりあえず: [Python][お勉強] Python入門(21) - range関数

[Python] 文字列から改行コードを取り除く方法 | 自由が丘で働くWeb屋のブログ