ウェブサイトをS3にバックアップする
実行中のウェブサイトをS3とCloudFrontにクローンする。
このPythonスクリプトの目的は、実行中のウェブサイトからすべてのページをS3バケットにバックアップまたは移行し、CloudFrontディストリビューションで提供することです。
私の使用ケースは単純で、ウェブサーバーに何か問題が発生した場合に備えて、ウェブサイトの安価なバックアップを取りたいのだ。現在、ウェブサイトを運営する最も安価な方法の1つは、ウェブ対応のS3バケットを持つことだ。非常に安いだけでなく、拡張性も抜群だ。
ウェブ対応S3バケット」と言っても、もちろん、もうみんなそんなことはしない(しないでほしい)、CloudFrontディストリビューションを前に置く(これも超スケーラブルで安価)。
この部分を始めるには、私のCloudFormationテンプレートを使うことができる。
コード
図書館
そのために、以下のPythonライブラリを使用する:
pip3 install --upgrade django-dotenv beautifulsoup4 lxml boto3
変数
AWS固有の変数を".env "ファイルから読み込みます(.gitignoreファイルで除外してください)。
S3ウェブサイトを実際のウェブサイトのフェイルオーバーにしたいので("ライブ "にするためにDNSレコードを再指定する必要があるだけ)、Bucket_name変数は、ファイルを取り出したい元のウェブサイトとS3バケット名で同じです。あなたのユースケースでは異なる名前が必要かもしれない。
extra_files変数は、sitemap.xmlファイルに含まれていない可能性のある、S3にバックアップしたい追加ファイルを含むリストです。
dotenv.read_dotenv()
backup_region_name = os.environ.get("backup_region_name", "")
backup_aws_access_key_id = os.environ.get("backup_aws_access_key_id", "")
backup_aws_secret_access_key = os.environ.get("backup_aws_secret_access_key", "")
html_mime_type = 'text/html; charset=utf-8'
bucket_name = 'www.example.com'
extra_files = ['/', '/robots.txt', '/sitemap.xml', 'favicon.ico']
s3 = boto3.resource(
's3',
region_name=backup_region_name,
aws_access_key_id=backup_aws_access_key_id,
aws_secret_access_key=backup_aws_secret_access_key,
)
ウェブページ一覧の取得
元のウェブサイトから引っ張ってくるすべてのウェブページのリストを得るために、私はサイトのsitemap.xmlファイルを使うことにした。100%完全ではないかもしれないが、最新のオプションのひとつであるはずだ。
get_sitemap関数の目的は、ウェブサイトからsitemap.xmlファイルを読み込み、すべての<loc>URIを列挙することです。各ページを読み込み、リターンコードが200の場合はSaveFile関数を呼び出してコンテンツをS3に保存します。
beautifulsoupでウェブページを読み込んでいるので、ページを解析し、任意の.cssファイルをextra_filesファイルリストに追加し、後で取得する。
def get_sitemap(url):
global extra_files
full_url = f"https://{url}/sitemap.xml"
with requests.Session() as req:
r = req.get(full_url)
soup = BeautifulSoup(r.content, 'lxml')
links = [item.text for item in soup.select("loc")]
for link in links:
r = req.get(link)
if r.status_code == 200:
html_content = r.content
else:
print(f'\033[1;31;1m{link} {r.status_code}')
continue
soup = BeautifulSoup(r.content, 'html.parser')
SaveFile(link, r.content, html_mime_type, soup.html["lang"])
# Get all CSS links
for css in soup.findAll("link", rel="stylesheet"):
if css['href'] not in extra_files:
print('\033[1;37;1m', "Found the URL:", css['href'])
extra_files.append(css['href'])
return
ウェブページをS3に保存する
SaveFile関数の目的は、ウェブページ、画像、.css、その他のファイルをS3に保存することです。コスト削減のため、S3には "REDUCED_REDUNDANCY "クラスを選択しました。
私は多言語のサイトを持っているので、'text/html; charset=utf-8'mime-typeを使用し、S3オブジェクトに設定できるようにHTMLファイルの言語も読み取ろうとしている。スクリプトはまた、URLをS3オブジェクトの適切な'utf-8'名に変換する。
私のウェブサイトは拡張子".html "を使用せず、ウェブページ名の最後に"/"を付加している。S3では、これはウェブページの名前を持つ "フォルダ "名と、HTMLコンテンツを含む"/"という名前のS3オブジェクトに変換される。
私のウェブサイトのデフォルトのルートページに'index.html'という名前をつけたのは、それがCloudFrontディストリビューションで設定されているデフォルトのウェブページだからだ。
def SaveFile(file_name, file_content, mime_type, lang):
global bucket_name
my_url = urllib.parse.unquote(file_name, encoding='utf-8', errors='replace')
my_path = urllib.parse.urlparse(my_url).path
if my_path == '/':
my_path = 'index.html'
if my_path.startswith('/'):
my_path = my_path[1:]
print(f'\033[1;32;1m{file_name} -> {my_path} {lang}')
bucket = s3.Bucket(bucket_name)
if lang is not None:
bucket.put_object(Key= my_path, Body=file_content, ContentType=mime_type, StorageClass='REDUCED_REDUNDANCY', CacheControl='max-age=0', ContentLanguage=lang)
else:
bucket.put_object(Key= my_path, Body=file_content, ContentType=mime_type, StorageClass='REDUCED_REDUNDANCY', CacheControl='max-age=0')
追加ファイルの保存
get_others関数の目的は、サイトマップファイルに含まれていない「余分な」ファイルを取得することです。これらには '/robots.txt'、'/sitemap.xml'、'favicon.ico' などが含まれます。mimetypesライブラリを使用して、適切なmime-typesタグを推測し、S3に設定します。同じSaveFile関数を呼び出してS3に保存する。
def get_others(url):
global extra_files
with requests.Session() as req:
for file in extra_files:
my_url = requests.compat.urljoin(f"https://{url}", file)
# Get MIME type using guess_type
mime_type, encoding = mimetypes.guess_type(my_url)
if mime_type is None:
mime_type = html_mime_type
print("\033[1;37;1mMIME Type:", mime_type)
r = req.get(my_url)
if r.status_code == 200:
if mime_type == html_mime_type:
soup = BeautifulSoup(r.content, 'html.parser')
lang = soup.html["lang"]
else:
lang = None
SaveFile(my_url, r.content, mime_type, lang)
else:
print(f'\033[1;31;1m{my_url} {r.status_code}')
continue
return
完成したコード
この記事の全ソースコードはhttps://github.com/Christophe-Gauge/python/blob/main/backup_website.py。
このスクリプトはすべてのユースケースに対応できるわけではありませんが、良いきっかけになれば幸いです。このスクリプトを改善する場合は、以下にコメントするか、プルリクエストを提出してください!
Tagged with:
AWS web