0
2

PythonのBeautiful Soupでwebサイトのリンクをたどってコンテンツ一覧を作成

Last updated at Posted at 2024-09-06

概要

webサイトに貼り付けられているCSVファイルやExcel、PDFファイルなどをリストアップするために作成。
基点となるURLを指定し、その中にあるリンクを再帰的に辿ってリンクのリスト、データファイルのリストをそれぞれTSVで出力。

使い方

・「base_url」に基点となるURLを設定。サイトマップとか。
・「def_recur_srch_cnt」で再帰探索する回数を指定。
・必要に応じてページ内で検索対象にするタグ、抽出対象とするURLのフィルタ条件を変更

ソースコード

import sys
import re
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

# url = sys.argv[1]
headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0",}

# リンクを再帰探索する数
def_recur_srch_cnt = 10

# ベースURL
base_url = "https://www.hogehoge.jp/sitemap.html"

# ファイル出力先フォルダ
out_dir = "C:\\work\\tmp\\"
# ファイル名
out_fname_dl = "datalink.txt"
out_fname_pl = "pagelink.txt"
out_fname_tl = "tableaulink.txt"
out_fname_ck = "checked_url.txt"

# 変数初期化
search_urls = []
checked_urls = []
tmp_urls = []
search_urls.append(base_url)

#ファイルオープン
f_dl = open(out_dir + out_fname_dl, "w", encoding='UTF-8')
f_pl = open(out_dir + out_fname_pl, "w", encoding='UTF-8')
f_tl = open(out_dir + out_fname_tl, "w", encoding='UTF-8')

# 初期設定で定義した数だけURL階層を再帰的に検索
for i in range(def_recur_srch_cnt):
	for url in search_urls:
		# 既にチェックしたURLでなければ処理を実行
		if not(url in checked_urls):
			try:
				rr = requests.get(url, headers=headers)
				html = rr.content
					soup = BeautifulSoup(html, "html.parser")
				
					# ページタイトルの取得
					pagetitle = soup.head.title.get_text()
					# リンク先抽出対象となるメインコンテンツ部分の指定
					elements = soup.body.find("div", id="main")
			except Exception as ee:
				sys.stderr.write("*** error *** in requests.get ***\n")
				sys.stderr.write(str(ee) + "\n")
			
			try:
				# ページリンクの抽出
				# .htm又は.htmlのページを対象とするが、"?!"に続くディレクトリを含むものは除外
				for aa in elements.find_all("a", href=re.compile(r'^(?=^(https://www.hogehoge.jp|/|\.+/).*html?[^\.]*$)(?!.*/(en|press)/.*)')):
					# 改行をスペースに置換の上、ドメイン名を省略している場合は付加
					link = re.sub(r'\n', " ", aa.get("href"))
					# さらに相対パスの場合は検索対象ページのURLを絶対パスに変換
					if link.startswith(".") or link.startswith("/"):
						link = urljoin(url, link)
					# リンク名取得
					name = re.sub(r'\n', " ", aa.get_text())
					# ファイル出力
					f_pl.write(str(i) + "\t" + url + "\t" + pagetitle + "\t" + link + "\t" + name + "\n")
					# アンカータグを削除した上で一時URLリストに追加
					tmp_urls.append(re.sub(r'#.+$', "", link))
				
				# データファイルへのリンクの抽出
				for aa in elements.find_all("a", href=re.compile(r'.*\.(csv|CSV|xlsx?|XLSX?|docx?|DOCX?|pptx?|PPTX?|pdf|PDF)$')):
					datalink = re.sub(r'\n', " ", aa.get("href"))
					datatype = re.sub(r'.*\.', "", datalink)
					dataname = re.sub(r'\n', " ", aa.get_text())
					f_dl.write(str(i) + "\t" + url + "\t" + pagetitle + "\t" + datatype + "\t" + datalink + "\t" + dataname + "\n")
			
			except Exception as ee:
				sys.stderr.write("*** error *** in BeautifulSoup ***\n")
				sys.stderr.write(str(ee) + "\n")
			
			# 抽出したリンク情報を重複削除の上で検索対象URLリストに追加)
			tmp_urls.sort()
			search_urls = list(set(tmp_urls))
			# チェック済URLとしてリストに追加
			checked_urls.append(url)
			
			# Sleep 2秒
			time.sleep(2)


#ファイルクローズ
f_dl.close()
f_pl.close()
f_tl.close()

# join()で要素内容を結合
s = "\n".join(checked_urls)
with open(out_dir + out_fname_ck, "w", encoding='UTF-8') as f:
	# 書き込み
	f.write(s)

特定のタグを指定する方法もある。

for aa in elements.find_all("div", class_="class_name"):
	id = aa.attrs['id']
	name = aa.noscript.a.img.attrs['alt']
	f_tl.write(str(i) + "\t" + url + "\t" + id + "\t" + name + "\n")

参考URL

0
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2