サイトマップからレンダリングされたリンクへ: フルサイトURL発見のための6つのメソッドスタック
Expert in Web Scraping Technologies
主なポイント:
- すべてのページをリストする単一のコマンドは存在しません。 完全なURLインベントリは、層を重ねた方法から得られます:迅速な見積もりのための
site:検索オペレーター、サイトが公開している内容のsitemap.xml及びサイトマップインデックス、エントリポイントに関するrobots.txtサイトマップディレクティブ、実際にリンクされているものを見つけるためのSEOクローラーまたはPythonクローラー、JavaScriptが実行された後にのみ表示されるクライアントサイドのリンク用のクラウドブラウザ。 - サイトマップは存在し、最新であれば最も迅速な権威あるソースです。 単一の
requests.get("/sitemap.xml")に加え、任意のサイトマップインデックスの再帰的ウォークは、一度の通過で数百のURLを返すことができます。 - 幅優先クローラーはサイトマップが省略したものを見つけます。 サイトマップは著者がキュレーションし、頻繁に古くなっているため、内部の
<a href>リンクのBFSウォークは、孤立したページ、ディープリンクされたコンテンツ、およびサイトマップが忘れたものを発見します。このガイドのクローラーは、URLをフェッチする前にすべてのURLでrobots.txtのDisallowルールを尊重します。 - JavaScriptでレンダリングされたリンクは実際のブラウザが必要です。 シングルページアプリや無限スクロールカタログは、内部リンクをクライアントサイドで描画するため、プレーンなHTTPフェッチではほぼ空のシェルが返されます。Scrapeless Scraping Browserはクラウドブラウザ内でページをレンダリングし、その後水分補給されたDOMからアンカーを収集します。—米国の住宅出口はセッションに固定されています。
- 無料で始められます。 新しいScrapelessアカウントには、無料のScraping Browserランタイムが含まれています—app.scrapeless.comで登録できます。
はじめに: 完全なURLインベントリが難しい理由
ウェブサイト上のすべてのページを知ることは、多くの作業の基礎です:技術的なSEO監査、コンテンツの移行、リンク切れのスイープ、すべての製品URLが必要な価格監視パイプライン、あるいは全テキストコーパスを欲するLLM取り込み作業。問題は、どのサイトも完全なリストを保証して渡さないことです。ホームページはほとんどのセクションにリンクし、サイトマップはいくつかのページを公開し、孤立したページ—直接リンクで到達できるがナビゲーションからはリンクされていない—は両方をすり抜けます。
既存のオプションはそれぞれ一部をカバーします。Googleのsite:オペレーターは迅速な公共の見積もりを提供しますが、結果には上限があり、インデックスされた内容のみを反映します。sitemap.xmlは、公開者が宣言することを選んだ内容について権威がありますが、古くなり、CMSが登録しなかったページを省略します。リンクを辿るクローラーはリンクされたグラフを見つけますが、プレーンHTTPクローラーは、ナビゲーションがクライアントサイドで描画されているJavaScriptが重いページでは空のシェルを返します。
このガイドは、コストと完全性の順に6つの方法を通じて説明します—安価で迅速なものから、徹底的でレンダリングされたものまで。Pythonの例は、静的層のためにrequestsと標準ライブラリを使用し、JavaScript層のためにはScrapeless Scraping Browserを介してクラウドブラウザを使用します。そのため、クライアントサイドのリンクが発見可能になります。米国の出口を固定し、ページをレンダリングし、アンカーを収集します。兄弟ガイドへのクロスリンクは最後にあります。
それで何ができるか
- 技術的SEO監査。 インデックス可能なすべてのURLを列挙し、その後、クローリングをサイトマップと比較して孤立したページやサイトマップが忘れたページを浮き彫りにします。
- コンテンツの移行。 再プラットフォームの前に完全なソースURLリストを構築し、切り替え後に404が発生しないようにし、古いパスを新しいパスにマッピングします。
- リンク切れのスイープ。 内部リンクグラフをウォークし、すべての宛先を記録し、非200ステータスを返すものにフラグを付けます。
- 価格とカタログモニタリング。 小売業者のすべての製品URL—JavaScriptでレンダリングされたものを含めて—を発見し、それを下流の抽出パイプラインに供給します。
- LLMコーパスの取り込み。 全コンテンツURLの完全なセットを生成し、テキスト抽出作業が深くリンクされた記事を見逃すことなく全公開コーパスを引き出せるようにします。
- 競合コンテンツマッピング。 サイトマップとリンクグラフから競合他社の公開セクション構造をインベントリし、そのコンテンツフットプリントのサイズを測ります。
なぜScrapeless Scraping Browserなのか
このガイドのほとんどは、Pythonの標準ライブラリとrequestsで実行されます—サイトマップやrobots.txtはプレーンテキストやXMLであり、静的リンククローラーに他のものは必要ありません。Scrapeless Scraping Browserは、ウェブクローラーやAIエージェント向けに設計されたカスタマイズ可能で検出回避機能を持つクラウドブラウザです; 必要なリンクがJavaScriptが実行された後にのみ存在する場合に手に取る層です。特にフルサイトURL探索に関しては、以下の利点があります:
- クラウドサイドのJavaScriptレンダリング、 そのため、一ページアプリ、無限スクロールカタログ、またはReact/Vue/Next.jsナビゲーションの内部リンクが、読まれるDOMに表示されます—空の
<div id="root">としてではありません。 - 米国の住宅プロキシ出口、 セッションごとに固定されていますので、地理的に制限されたサイトが米国訪問者に提供するのと同じページ構造を提供します。
- すべてのセッションでの検出回避フィンガープリンティング、 そのため、レンダリングされたページはオーガニックトラフィックが見るものと一致し、フラグが立てられた自動化プロファイルとは異なります。
- セッションの連続性 ホームページ訪問によって設定されたクッキーが、実際に列挙したいページに引き継がれるため、ウォームアップナビゲーションとターゲットページ間にセッションが持続します。
- 1つのエンドポイント、標準CDP Playwright(または任意のChrome DevTools Protocolクライアント)が、ローカルブラウザによるレンダリングなしにWebSocketを介して接続します。
無料プランでAPIキーを取得するには、app.scrapeless.comにアクセスしてください。
前提条件
- Python 3.10以上
- ScrapelessアカウントとAPIキー — app.scrapeless.comでサインアップ
pip install requests playwrightおよびplaywright install chromium(ローカルのChromiumはCDPプロトコルクライアントのみで、レンダリングはScrapelessのクラウドで実行されます)- ターミナルとHTTPの基本的な理解
方法1 — Googleの site: 検索演 operator
最も迅速な最初の推定は、コードを必要としません。これをGoogleに入力してください:
site:example.com
Googleは、そのホストに対してインデックスされたページを返し、結果のヘッダーにおおよそのカウントが表示されます。セクション構造をマッピングするために絞り込みます:
site:example.com/blog—/blog以下のURLのみsite:example.com inurl:product— パスにproductを含むインデックスされたURLsite:example.com -inurl:tag— 無視したいパスセグメントを除外
この方法の利点:サイトの規模や存在するセクションを三十秒で把握できます。ただし、完全性には適していません。site: 演算子はGoogleが選択したページだけを反映し、結果の数は正確な数字ではなく推定です。また、この演算子はページを通じてどれだけの結果を取得できるかに制限があります。以下のより徹底した方法に対する正気のチェックとして扱ってください。サイトマップが5,000 URLを宣言し、site: が約200を示す場合、その差は自体が発見です。
方法2 — sitemap.xml とサイトマップインデックスを解析
サイトマップは、発行者自身によるURLの宣言であり、通常のパス /sitemap.xml でXMLとして提供されます。存在し、最新であれば、最も速く信頼できる情報源です。重要な形状は2つです:
<urlset>サイトマップは、ページのURLを直接リストします。各ページにつき1つの<url><loc>…</loc></url>。<sitemapindex>は 他のサイトマップ をリストします — 大規模なサイトは、子ファイル(pages_sitemap.xml、blog_sitemap.xmlなど)にURLを分割し、1つのインデックスからそれらを指します。まずインデックスをたどり、次に各子をたどります。
この requests スクリプトは、単一の再帰関数で両方の形状に対応します。ルートタグを検出し、サイトマップインデックスに再帰し、各<urlset>からページURLを収集します:
python
import requests
import xml.etree.ElementTree as ET
from urllib.parse import urljoin
SM_NS = "{http://www.sitemaps.org/schemas/sitemap/0.9}"
HEADERS = {"User-Agent": "Mozilla/5.0 (sitemap-discovery)"}
def walk_sitemap(url, seen=None):
"""サイトマップまたはサイトマップインデックスから到達可能なすべてのページURLを返します。"""
seen = seen if seen is not None else set()
if url in seen: # 自己参照するサイトマップを防ぐ
return []
seen.add(url)
resp = requests.get(url, headers=HEADERS, timeout=30)
resp.raise_for_status()
root = ET.fromstring(resp.content)
tag = root.tag.split("}")[-1] # 名前空間を削除し、「sitemapindex」または「urlset」を保持
urls = []
if tag == "sitemapindex":
# インデックスは子サイトマップを指します — 各サイトマップに再帰します。
for sm in root.findall(f"{SM_NS}sitemap"):
loc = sm.findtext(f"{SM_NS}loc")
if loc:
urls.extend(walk_sitemap(loc.strip(), seen))
else:
# urlsetはページURLを直接リストします。
for u in root.findall(f"{SM_NS}url"):
loc = u.findtext(f"{SM_NS}loc")
if loc:
urls.append(loc.strip())
return urls
if __name__ == "__main__":
pages = walk_sitemap("https://example.com/sitemap.xml")
print(f"サイトマップツリーから{len(pages):,} URLs を発見しました")
for u in pages[:10]:
print(" ", u)
/sitemap.xml が子サイトマップを指すサイトマップインデックスであるサイトに対して実行すると、再帰的な走査はすべての子サイトマップの結合を一度のパスで返します。
実際のサイトマップに関するいくつかのメモ:
- パスは慣習であって保証ではありません。
/sitemap.xmlは一般的な場所ですが、サイトは任意の名前を付けることができ、robots.txtに実際のパスを宣言できます(方法3)。ファイルが存在しないと仮定する前に、常にrobots.txtを確認してください。 - 圧縮されたサイトマップも存在します。 一部のサイトでは
sitemap.xml.gzが提供されており、requestsは.gzボディを自動的に解凍しないため、出くわした場合はgzipモジュールで解凍してから解析してください。 - サイトマップは古くなります。 それは生成時にCMSが登録した内容を反映しています。最後のビルド以来追加されたページや、CMSが登録しなかった孤立ページは欠落しており、これがメソッド5および6の存在理由です。
メソッド3 — robots.txtサイトマップディレクティブの読み取り
何かをクロールする前に、/robots.txtを取得します。URL発見のために二つの目的を持っています:それはしばしば一つ以上のSitemap:行でサイトマップの場所を宣言し、クロウラーに無視してほしいパスを示します(Disallow:)。両方重要で、最初はメソッド2にフィードし、二つ目はメソッド5に持ち込むコンプライアンス義務です。
python
import requests
from urllib.parse import urljoin
HEADERS = {"User-Agent": "Mozilla/5.0 (sitemap-discovery)"}
def sitemaps_from_robots(base_url):
"""robots.txtで宣言されたすべてのSitemap:ディレクティブを抽出します。"""
resp = requests.get(urljoin(base_url, "/robots.txt"), headers=HEADERS, timeout=30)
resp.raise_for_status()
sitemaps = []
for line in resp.text.splitlines():
if line.lower().startswith("sitemap:"):
sitemaps.append(line.split(":", 1)[1].strip())
return sitemaps
if __name__ == "__main__":
for sm in sitemaps_from_robots("https://example.com"):
print("宣言されたサイトマップ:", sm)
サイトのrobots.txtはしばしば一つ以上のSitemap:行を宣言します — 例えば Sitemap: https://example.com/sitemap.xml。それらをメソッド2のwalk_sitemapに直接渡せば、パスを推測することなく発行者の完全な宣言されたURLセットを得ることができます。
この組み合わせのパターンは静的発見の基盤です:robots.txtを読んでサイトマップや禁止されたパスを見つけ、その後すべての宣言されたサイトマップを歩きます。それら二つが返すものがあなたの権威あるスターティングインベントリです。この後のすべては、彼らが見逃したページを見つけることについてです。
無料プランでAPIキーを取得してください: app.scrapeless.com
メソッド4 — SEOクローラー(ノーコードオプション)
Pythonを書くのが嫌な場合は、デスクトップやクラウドのSEOクローラーが発見、リンクグラフのマッピング、レポートを一つのツールで行います。一般的なもの — Screaming Frog SEO Spider、Sitebulb、AhrefsやSemrushに組み込まれたサイト監査クローラーは、すべて同じ基本的な仕事を行います:スタートURLを種にして、内部リンクを幅優先でたどり、発見したすべてのURLのテーブルを生成します。ステータスコード、タイトル、深さ、外部リンクの数が含まれます。
これらのツールは以下のような場合に適しています:
- コードを維持せずに視覚レポートとCSVエクスポートが必要な場合。
- 標準のSEO列(ステータス、カノニカル、インデクサビリティ、リダイレクトチェーン)が計算されている必要がある場合。
- サイトがほとんどサーバーでレンダリングされたHTMLであり、デスクトップクローラーがネイティブに処理できる場合。
その限界を知っておく価値があります:無料プランはURL数を制限し(Screaming Frogの無料エディションは500URLで停止)、JavaScriptレンダリングはオプションの遅いモードであり、すべてのプランが有効にするわけではありません。また、クラウドの監査ツールはプロジェクトサイズによって価格が決まります。小さなサイトの一回限りの監査には非常に良いですが、別のシステムにデータとしてURLを提供するための再現可能なパイプラインの場合、以下のプログラム手法がレポートではなくデータとしてURLを提供します。次の2つのメソッドはそのプログラム的経路です。
メソッド5 — Python BFS内部リンククローラー
サイトマップが古いか存在しない場合、検索エンジンのようにページを発見します:ホームページから始めて、すべての内部<a href>を解析し、まだ見ていないものをキューに追加し、フロンティアが空になるかページ制限に達するまで幅優先で繰り返します。これにより、サイトマップで宣言されていない孤立ページや深くリンクされたページを見つけることができます。
リンククローラーには妥協の余地のない二つの責任がありますが、どちらも以下のコードに組み込まれています:
robots.txtを尊重する。 各URLをリクエストする前にcan_fetchをチェックし、サイトが禁止しているものはスキップします。標準ライブラリのurllib.robotparserがルールを読み、評価します。- ホスト内に留まり、重複を排除する。 スタートホストと一致するホストのリンクのみをキューに追加し、URLフラグメントを削除して
/pageと/page#sectionが一度だけカウントされるようにし、リンクグラフでのサイクルが無限にループしないようにseenセットを保ちます。
python
import requests
from collections import deque
from html.parser import HTMLParser
from urllib.parse import urljoin, urldefrag, urlparse
from urllib.robotparser import RobotFileParser
HEADERS = {"User-Agent": "Mozilla/5.0 (link-discovery)"}
class LinkParser(HTMLParser):
"""ページ内の<a>タグからすべてのhrefを集めます。"""
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
if tag == "a":
for key, value in attrs:
if key == "href" and value:
self.links.append(value)
def load_robots(base_url):
rp = RobotFileParser()
rp.set_url(urljoin(base_url, "/robots.txt"))
ja
rp.read() # Disallowルールとcrawl-delayを解析します
return rp
def crawl(start_url, max_pages=200, user_agent="*"):
"""robots.txtを尊重しながら内部リンクを幅優先で探索します。"""
host = urlparse(start_url).netloc
robots = load_robots(start_url)
seen = {start_url}
queue = deque([start_url])
found, skipped = set(), []
while queue and len(found) < max_pages:
url = queue.popleft()
# コンプライアンスゲート: サイトが禁止しているパスを取得しない。
if not robots.can_fetch(user_agent, url):
skipped.append(url)
continue
try:
resp = requests.get(url, headers=HEADERS, timeout=30)
resp.raise_for_status()
except requests.RequestException:
# 単一の不正なURLは、バンド外で記録され、インラインで追跡されません。
continue
if "text/html" not in resp.headers.get("Content-Type", ""):
continue
found.add(url)
parser = LinkParser()
parser.feed(resp.text)
for href in parser.links:
absolute = urldefrag(urljoin(url, href))[0] # 解決して#fragmentを削除
if urlparse(absolute).netloc == host and absolute not in seen:
seen.add(absolute)
queue.append(absolute)
return found, skipped
if __name__ == "__main__":
pages, disallowed = crawl("https://example.com/", max_pages=200)
print(f"発見したページ: {len(pages):,}件; robots.txtにより{len(disallowed)}件スキップ")
このクローラーを静的デモカタログに対して実行したところ、上限を40に設定して40ページを発見し、スキップされたURLはゼロでした。このサイトのrobots.txtは何も禁止していません。robots.txtがパスを禁止しているサイトに向けた場合、同じクローラーは正しく禁止されているURLを拒否し、それをスキップリストに記録しました — すべてのURLに対してコンプライアンスが強制され、後回しではありません。
これが以前の方法とどのように組み合わさるか:
- クローラーはサイトマップが省略したものを見つける; サイトマップはクローラーがリンクで到達できないものを見つける。両方を実行して、最も完全なインベントリを得る。
- 失敗はバンド外に保たれる。 エラーが発生したURLはこのパスから除外され、クローリングは継続 — 1件の不正ページが全体の歩行を停止させることはありません。ドロップされたURLは別途収集してレビューします。
- 礼儀のために同時実行を制限する。 上記のような単一スレッドクローラーはすでに穏やかです。並列処理する場合は、ホストごとに3ワーカー以下に保ち、robots.txtが宣言するいかなる
Crawl-delayも尊重してください。 - クローラーはHTMLのみ。 ロード後にJavaScriptによって描画されたリンクは
requestsには見えません。このギャップがまさに方法6で解消されます。
方法6 — Scrapeless Scraping Browserを使用してJavaScript重視のページをレンダリング
requestsベースのクローラーは、サーバーが送信するバイトを読み取ります。シングルページアプリ、無限スクロールカタログ、またはReact/Vue/Next.jsナビゲーションにおいて、それらのバイトはアプリのシェル — <div id="root"></div>プラススクリプトタグ — であり、内部リンクはバンドルが実行されるとクライアントサイドで描かれます。通常のHTTPはそれらを見ることができません; 実際のブラウザはできます。
Scrapeless Scraping Browserはクラウドブラウザでページをレンダリングし、Chrome DevTools Protocolを介してそれを公開します。WebSocketエンドポイントを介してPlaywrightと接続し、ホームページを温めてセッションがクッキーを持ち運ぶようにし、ターゲットに移動し、次に水分補給されたDOMからアンカーを収集します — 方法5のリンク解析ステップのレンダリングページアナログです。USの出口はセッションに固定されているため、地理で制限されたサイトは標準構造を提供します。
接続はAPIキーから構築された単一のWebSocket URLです。これが正確な接続形状です:
python
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright
def scraping_browser_url(proxy_country="US", session_ttl=240):
params = urlencode({
"token": os.environ["SCRAPELESS_API_KEY"],
"sessionTTL": session_ttl,
"proxyCountry": proxy_country,
})
return f"wss://browser.scrapeless.com/api/v2/browser?{params}"
エンドポイントを手に入れたら、ターゲットをレンダリングし、その内部リンクを収穫します:
python
from urllib.parse import urljoin, urldefrag, urlparse
def discover_rendered_links(start_url, proxy_country="US"):
"""クラウドブラウザでJS重視のページをレンダリングし、同一ホストのリンクを収集します。"""
host = urlparse(start_url).netloc
homepage = f"{urlparse(start_url).scheme}://{host}/"
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(scraping_browser_url(proxy_country))
context = browser.contexts[0] if browser.contexts else browser.new_context()
page = context.pages[0] if context.pages else context.new_page()
# まずホームページを温め、セッションがクッキーを持ち運ぶようにし、次にターゲットへ移動します。
page.goto(homepage, wait_until="domcontentloaded", timeout=60_000)
page.goto(start_url, wait_until="networkidle", timeout=60_000)
ハイドレーションされたDOMからhrefを読み取り、クライアントサイドのレンダリングが完了した後。
hrefs = page.eval_on_selector_all(
"a[href]", "els => els.map(e => e.getAttribute('href'))"
)
browser.close()
links = set()
for href in hrefs:
if not href:
continue
absolute = urldefrag(urljoin(start_url, href))[0]
if urlparse(absolute).netloc == host:
links.add(absolute)
return links
if name == "main":
found = discover_rendered_links("https://example.com/app/catalog")
print(f"レンダリング後に発見されたクライアントサイドのリンク: {len(found):,}件")
for u in sorted(found)[:10]:
print(" ", u)
この信頼性をもたらすパターン:
- ホームページを温めてからナビゲートする。 最初の
gotoを/にすることで、セッションがクッキーを取得し、サイトの初回ロードチェックを通過する; 2回目のgotoは、実際に列挙したいページに到達する。コールドセッションで深いURLに直行するのは、チャレンジが発生する可能性が高い。 - ターゲットで
wait_until="networkidle"を使用することで、クライアントサイドのルーターがリンクをマウントする時間を与えた後にDOMを読み取る。無限スクロールページに対しては、リンクの数が増えなくなるまでループで下にスクロールし(page.mouse.wheel)、その後収集する。 - レンダリングはScrapelessのクラウドで実行され、 あなたのマシン上ではない。ローカルの
playwright install chromiumは、wss://browser.scrapeless.com/...エンドポイントと通信するCDPクライアントだけである。 - 結果をユニオンにフィードバックする。 レンダリングされたリンクはサイトマップセットと静的クロールセットに結合され、最終的なインベントリでは正規化されたURLで重複を排除する。
これを完全なクローラーに組み込むには、Method 5のrequests.get本体をJavaScript-heavyのホストに対してdiscover_rendered_linksに置き換え、サーバーサイドレンダリングの大多数には安価なrequestsパスを維持する。そのHTTPファースト、ブラウザセカンドの分割により、クラウドブラウザの使用は実際に必要なページのみに抑えられる。
得られるもの
各メソッドは絶対URLのセットを出力し、最終的なインベントリはそれら全体の重複を取り除いたユニオンである。1つのホストのマージされたレコードは次のように見える:
json
// スキーマは4つのプログラム的メソッドのユニオンを反映する。
// カウントは例示用サンプルであり、現在のサイトの固定スナップショットではない。
{
"host": "example.com",
"discovered_at_methods": ["sitemap", "robots", "bfs_crawl", "rendered"],
"counts": {
"from_sitemap": 226,
"from_bfs_crawl": 40,
"from_rendered": 18,
"union_unique": 248
},
"sample_urls": [
"https://example.com/",
"https://example.com/blog",
"https://example.com/blog/how-to-scrape-bbb-business-listings",
"https://example.com/app/catalog?page=2"
],
"skipped_by_robots": [
"https://example.com/private/"
]
}
ウェブサイト全体のURL発見についての注目すべき観察点は、スケールで実行する前に知っておく価値がある:
- ユニオンは単一のソースに勝る。 サイトマップは発行者が登録したものを宣言する; BFSクロールはリンクされた孤児を見つける; レンダリングパスはクライアントサイドのリンクを見つける。カバレッジは3つ全てのユニオンであり、禁止されたパスを除く。
- 正規化されたURLで重複を排除する。 フラグメントを取り除き、末尾のスラッシュや
?utm_*クエリパラメータがあなたのケースで重要かどうかを決定し、カウントの前に正規化する - さもなければ/pageと/page/が総数を膨らませる。 - サイトマップはコンテンツに遅れをとる。 最後のサイトマップのビルド後に公開されたページはクロール層にのみ表示される。完全なインベントリが重要な場合は、常にサイトマップの読み込みと一緒にクロールを実行する。
- クライアントサイドのリンクはHTTPには見えない。 知っている大規模サイトの
requestsクロールがほんの数件のURLしか返さない場合、ナビゲーションはほぼ確実にクライアントサイドでレンダリングされている - そのホストをMethod 6にエスカレートする。 - 禁止リストを最初から最後まで尊重する。
skipped_by_robots配列はTODOリストではない。それらのパスはインベントリに残らない。
結論:完全なURLインベントリを構築する
すべてのページを発見することは、次の4つのプログラム的な手順に1つの手動チェックを重ねたものに帰着する:site:でサイズを推定し、サイトマップの場所と禁止されたパスのためにrobots.txtを読み、宣言されたURLのためにサイトマップツリーを歩き、孤児のために内部リンクグラフをBFSクロールし、クライアントサイドのリンクのためにクラウドブラウザでJavaScript-heavyのホストをレンダリングする。ユニオンを取り、正規化されたURLで重複を排除することが、そのインベントリである。
プロキシ層に関しては、レンダリングされたティアをルーティングします。詳細はSSLプロキシとは?をご覧ください。Scraping Browser製品ページと料金ページはクラウドブラウザのティアをカバーしています。完全なSDKリファレンスはdocs.scrapeless.comにあります。レンダリングされたティアで米国の出口を固定し、ターゲットページの前にホームページをウォームアップし、すべてのURLでrobots.txtを尊重し、最終リストをすべてのメソッドの合併として扱います。
AI搭載のデータパイプラインの構築準備は整いましたか?
私たちのコミュニティに参加して無料プランを請求し、URL発見やクロールパイプラインを構築している開発者とつながりましょう:Discord · Telegram。
app.scrapeless.comにサインアップして無料のScraping Browserランタイムを利用し、上記のパターンをパイプラインが必要とするサイト、サイトマップ、地域に適応させてください。
よくある質問
Q: ウェブサイトをクロールしてすべてのページを見つけることは合法ですか?
発見自体は公開されているURLを読み取りますが、合法性はあなたがアクセスする内容、場所、条件に依存します。サイトのrobots.txtを尊重し、サービス利用規約を確認し、プライベートまたは認証が必要なエリアを避け、高リスクの使用ケースについては法律相談を行ってください。Scrapelessは公開されているデータのみをアクセスします。
Q: サイトマップとクロール — どちらが完全なリストを提供しますか?
どちらも単独では不十分です。サイトマップは発行者の宣言であり、しばしば古くなっていたり不完全であるため、クロールは関連するグラフを見つけますが、ページへのリンクがないページは見逃します。完全な在庫は、サイトマップの探索(方法2)とBFSのクロール(方法5)の合併であり、クライアントサイドのリンクのためにレンダリングされたティア(方法6)が追加されます。
Q: 私のクロールツールが大規模なサイトでわずかなページしか見つけられないのはなぜですか?
そのサイトはほぼ確実にクライアントサイドでナビゲーションをレンダリングしています。単純なrequestsフェッチはJavaScriptが実行される前にアプリシェルを返すため、フォローするリンクが存在しません。Scrapeless Scraping Browser(方法6)でそれらのホストをレンダリングし、ハイドレートされたDOMからアンカーを収集してください。
Q: URLの発見にプロキシは必要ですか?
単一ホストのサイトマップを読み取り、丁寧な静的クロールでは、しばしば必要ありません。サイトがgeo-gateコンテンツを持っている場合(米国の構造を表示するには米国の出口が必要)、IPがレート制限されている場合、またはレンダリングされたティアが有機的なトラフィックに合わせるために住宅の出口が必要な場合、プロキシがその価値を発揮します。方法6のScrapeless接続はproxy_country="US"で出口を固定します。
Q: ページがアクセスチャレンジを提供した場合、クリーンなレンダリングを得るにはどうしますか?
セッションに米国の住宅出口を固定し、セッションをウォームアップします。ターゲットページの前に同じブラウザセッションでサイトのホームページにナビゲートします。方法6のコードがそうであるように、クッキーが設定され、深いページがすでに信頼されたコンテキストでロードされるようにします。深いURLに直接飛ぶことは、チャレンジを引き起こす可能性が高くなります。
Q: サイトがHTMLまたはリンク構造を変更した場合どうなりますか?
静的なクロールは一般的な<a href>要素にキーを持っているため、マークアップの変更はほとんどそれを壊しません。レンダリングされたティアのセレクターを特定のコンテナに絞り込んでいる場合、マークアップがシフトした際に再チェックし、サイトがナビゲーションを再編成した場合はa[href]に戻るように広げてください。
Q: クロール中にサイトを叩くのを避けるにはどうしますか?
方法5のシングルスレッドクロールはすでに優しいです。並列化する場合は、ホストごとに3ワーカーを超えないようにし、robots.txtにあるCrawl-delayディレクティブを尊重し、禁止ルールにカバーされるパスを決してキューに入れないでください。
Q: 最終的なURLセットの重複を排除するにはどうしますか?
カウントの前に正規化します:#fragmentsを削除し、トレーリングスラッシュとトラッキングクエリパラメータ(?utm_*)が使用ケースにとって重要かどうかを決定し、正規化された形式をキーにしてURLをsetに保存します。各メソッドはすでにsetを返します。それらすべての合併を取り、重複を排除します。
Q: AIエージェントやSDKなしでURLを発見できますか?
はい。メソッド1〜5はPythonの標準ライブラリとrequestsのみを使用します。メソッド6はCDPを通じてScrapeless Scraping Browserエンドポイントに接続するPlaywrightを追加します — エージェントフレームワークは必要なく、APIキーから構築されたWebSocket URLだけで済みます。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



