ブログに戻る

ニュースサイトをブロックなしでスクレイピングする方法:プロキシ設定と保護回避

ニュースサイトのスクレイピング設定に関する完全ガイド:プロキシの種類の選択、アンチボットシステムの回避、IPローテーションの設定、Pythonのコード例。

📅2026年3月7日
```html

ニュースサイトは、インターネット上で最も保護されたリソースの一つです。Cloudflare、レート制限、IPによるブロックなど、これらはニュースのスクレイピングを深刻な技術的課題にしています。このガイドでは、ニュースポータルからのデータ収集を安定させるためのプロキシの正しい設定方法、さまざまなタスクに適したプロキシの種類、そして最新の保護システムを回避する方法について説明します。

なぜニュースサイトはスクレイパーをブロックするのか

ニュースポータルは、自動データ収集に対して特に敏感です。その理由は主に2つあります。第一に、コンテンツは彼らの主要な資産であり、広告やサブスクリプションを通じて収益化されています。大量のスクレイピングは競合他社に資料をコピーさせ、ユニークな訪問者数を減少させます。第二に、ボットからの高負荷はサーバーやCDNのコストを増加させます。

現代のニュースサイトは多層的な保護を使用しています:

  • Cloudflareや類似のサービス — JavaScript、TLSフィンガープリンティング、行動パターンをチェックします。
  • レート制限 — 一つのIPからのリクエスト数を制限します(通常は1分あたり10-50リクエスト)。
  • User-Agentによるブロック — 標準的なライブラリのヘッダー(Python-requests、curl)を禁止します。
  • CAPTCHA — 疑わしい活動があった場合に表示されます。
  • ジオブロック — 一部のニュースポータルは特定の国からのみアクセス可能です。

ニュースサイトがスクレイパーを検出する典型的な兆候:同じIPが連続して多くのリクエストを行う、JavaScriptがない、HTTPヘッダーの順序が標準的でない、リクエストの速度が速すぎる(人間は1秒間に10ページを開くことはできません)、クッキーやリファラーがないことです。

重要: ニュースサイトのスクレイピングはグレーゾーンにあります。ターゲットリソースのrobots.txtと利用規約を常に確認してください。データの商業利用には、公式APIを使用するか、パートナーシップ契約を結ぶことをお勧めします。

ニューススクレイピングに適したプロキシの種類

プロキシの種類の選択は、タスクの規模、予算、ターゲットサイトの保護レベルによって異なります。ニューススクレイピングに適した3つの主要なオプションとその適用性を見ていきましょう。

プロキシの種類 速度 コスト 使用するタイミング
データセンターのプロキシ 高速(50-100 ms) 低コスト Cloudflareのないサイト、大量データ、テスト
レジデンシャルプロキシ 中速(200-500 ms) 高コスト Cloudflareのあるサイト、厳しい保護、ジオターゲティング
モバイルプロキシ 中速(300-600 ms) 非常に高コスト 最大の保護、ニュースサイトのモバイル版

ニューススクレイピング用のデータセンターのプロキシ

深刻な保護のないニュースサイトのスクレイピングに適しています:地域の出版物、ブログ、小規模な情報ポータル。利点:高速(数百のソースをスクレイピングする際に重要)、低コスト(50-100のIPプールをレンタル可能)、安定した接続。

欠点:ASN(データセンターへの帰属)によって簡単に検出され、大規模なサイトのブラックリストに載っていることが多く、70%の確率でCloudflareチャレンジを通過しません。データセンターのプロキシは、RSSフィード、sitemap.xml、APIエンドポイントの大量スクレイピングや、完全なコンテンツをダウンロードせずにメタデータ(タイトル、公開日)を収集するために使用してください。

レジデンシャルプロキシ — ゴールドスタンダード

レジデンシャルプロキシは、インターネットサービスプロバイダーによって提供される実際の家庭ユーザーのIPアドレスです。ニュースサイトにとって、彼らは通常の訪問者のように見えるため、保護されたリソースで作業する際に非常に重要です。

レジデンシャルプロキシが必須な場合:大規模なニュースポータル(CNN、BBC、Reuters、RBK、コメルサント)のスクレイピング、Cloudflareや類似の保護のあるサイト、特定の国からのデータ収集(ジオターゲティング)、認証を伴う長時間のセッション。レジデンシャルプロキシはCloudflareのJavaScriptチェックを通過し、クリーンなIPの評判を持ち、スティッキーセッション(10-30分のIP固定)をサポートします。

実用的なアドバイス:リクエストごとにIPを変更するのではなく、時間によるローテーション(スティッキーセッション)を持つレジデンシャルプロキシを使用してください。例えば、1つのIPが10分間機能し、20-30の記事を収集した後に変更されます。これは、リクエストごとにIPを変更するよりも自然に見えます。

特別な場合のモバイルプロキシ

モバイルプロキシは、モバイルオペレーター(MTS、ビライン、Tele2)のIPを使用します。彼らは最大の信頼を持っており、何百万もの人々がニュースを読むためにモバイルインターネットを使用しています。モバイル版のニュースサイトのスクレイピング(通常は簡素化された保護がある)や、極めて厳しい保護のあるサイト、GoogleニュースのAMPページに適用してください。

モバイルプロキシの特徴:IPは自動的に頻繁に変更されます(モバイルオペレーターはCGNATを使用)、1つのIPは同時に数百のユーザーに属する可能性があるため、ブロックは無意味になります。欠点は高コストであるため、最も保護された目的のためにのみ使用してください。

Cloudflareやその他のアンチボットシステムの回避

Cloudflareはニュースサイトのスクレイパーにとって最大の敵です。約40%の大規模なニュースポータルがボットからの保護のためにCloudflareを使用しています。標準的なライブラリ(requests、urllib)はチェックを通過しません。なぜなら、CloudflareはTLSフィンガープリンティング、JavaScriptの実行、HTTPヘッダーの順序、行動パターンを分析するからです。

Cloudflareを回避するための戦略

1. ヘッドレスブラウザ(Selenium、Playwright、Puppeteer)

JavaScriptを実行するリアルブラウザをエミュレートします。CloudflareはChrome/Firefoxの正しいTLSフィンガープリンティングを確認し、リクエストを通過させます。欠点:遅い(ページあたり2-5秒)、多くのリソース(RAM、CPU)を必要とします。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# Selenium用のプロキシ設定
chrome_options = Options()
chrome_options.add_argument('--proxy-server=http://username:password@proxy.example.com:8080')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')

driver = webdriver.Chrome(options=chrome_options)
driver.get('https://news-site.com/article')

# JavaScriptの読み込みを待つ
driver.implicitly_wait(10)
html = driver.page_source
driver.quit()

2. TLSフィンガープリンティングを持つライブラリ(curl_cffi、tls-client)

ヘッドレスブラウザを起動せずに、リアルブラウザのTLSフィンガープリンティングを模倣します。Seleniumよりも10-20倍速く動作しますが、JavaScriptは実行しません。基本的なCloudflareチェック(JSチャレンジなし)のあるサイトに適しています。

from curl_cffi import requests

proxies = {
    'http': 'http://username:password@proxy.example.com:8080',
    'https': 'http://username:password@proxy.example.com:8080'
}

response = requests.get(
    'https://news-site.com/article',
    proxies=proxies,
    impersonate='chrome110'  # Chrome 110のTLSフィンガープリンティングを模倣
)

print(response.text)

3. Cloudflareバイパスサービス(scraperapi、scrapingbee)

Cloudflareを自動的に回避する有料APIです。URLを送信すると、準備されたHTMLが返されます。利点:技術的な詳細を理解する必要がなく、自動的にプロキシをローテーションし、CAPTCHAを処理します。欠点:大規模なボリュームでは高額(100Kリクエストあたり$50から)。

正しいHTTPヘッダー

プロキシを使用している場合でも、正しいヘッダーを送信することが重要です。そうしないと、サイトは非標準のUser-AgentやAccept-Languageの欠如からボットを特定します。

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'DNT': '1',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
    'Cache-Control': 'max-age=0'
}

定期的にUser-Agentを更新してください — 最新のブラウザバージョンを使用します。自分のフィンガープリンティングをwhoer.netやbrowserleaks.comで確認できます。

IPのローテーション設定とリクエスト管理

プロキシの正しいローテーションは、ブロックなしで安定したスクレイピングの鍵です。ニュースサイトは、1つのIPからのリクエストの頻度を追跡し、制限を超えると一時的または永久的に禁止されます。

プロキシのローテーションの種類

リクエストごとのローテーション — 各リクエストは新しいIPを通過します。多くの異なるサイトを迅速にスクレイピングするのに適しており、リクエストの頻度による禁止のリスクを最小限に抑えます。欠点:セッションのあるサイト(クッキー、認証)には適しておらず、一部の保護には疑わしく見える可能性があります。

時間によるローテーション(スティッキーセッション) — 1つのIPが固定された時間(5-30分)使用され、その後変更されます。多くのページを持つ1つのニュースポータルのスクレイピングに適しており、クッキーやセッションを保持し、実際のユーザーの行動のように見えます。ほとんどのニューススクレイピングタスクに推奨されます。

ジオロケーションによるローテーション — 異なる国/都市からのIPの変更。ジオ依存コンテンツ(地域ニュース)のスクレイピングや、ジオブロックの回避に使用されます。

最適なリクエストの頻度

プロキシのローテーションがあっても、リクエストを頻繁に行うことはできません。さまざまなタイプのサイトに対する安全なインターバル:

  • 大規模なニュースポータル(RBK、コメルサント、ベドモスチ) — 1つのIPからのリクエスト間隔は2-5秒
  • 中規模のサイト — 1-3秒
  • 小規模なブログや地域の出版物 — 0.5-1秒

リクエストのパターンが自然に見えるように、ランダムな遅延を追加してください:

import time
import random

def fetch_article(url, proxies):
    response = requests.get(url, proxies=proxies, headers=headers)
    
    # 2から5秒のランダムな遅延
    delay = random.uniform(2, 5)
    time.sleep(delay)
    
    return response.text

プールからのプロキシのローテーションの例

プロキシのリストがある場合、手動で簡単なローテーションを実装できます:

import itertools
import requests

# プロキシプール
proxy_list = [
    'http://user:pass@proxy1.example.com:8080',
    'http://user:pass@proxy2.example.com:8080',
    'http://user:pass@proxy3.example.com:8080',
]

# 無限イテレータを作成
proxy_pool = itertools.cycle(proxy_list)

def get_next_proxy():
    proxy = next(proxy_pool)
    return {'http': proxy, 'https': proxy}

# 使用例
urls = ['https://news1.com/article', 'https://news2.com/article']

for url in urls:
    proxies = get_next_proxy()
    response = requests.get(url, proxies=proxies, headers=headers)
    print(f'Fetched {url} via {proxies["http"]}')

コード例:Python + Scrapy + プロキシ

Scrapyは、プロキシ、ミドルウェア、ローテーション、エラーハンドリングをサポートするプロフェッショナルなスクレイピングフレームワークです。プロキシのローテーションを含むニュースサイトのスクレイパーの完全な例を見ていきましょう。

依存関係のインストール

pip install scrapy scrapy-rotating-proxies

プロキシを使用したScrapyの設定(settings.py)

# settings.py

# プロキシのローテーション用ミドルウェアを有効にする
ROTATING_PROXY_LIST = [
    'http://user:pass@proxy1.example.com:8080',
    'http://user:pass@proxy2.example.com:8080',
    'http://user:pass@proxy3.example.com:8080',
]

DOWNLOADER_MIDDLEWARES = {
    'rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
    'rotating_proxies.middlewares.BanDetectionMiddleware': 620,
}

# ブロック回避のための設定
CONCURRENT_REQUESTS = 8  # 同時リクエストは最大8
DOWNLOAD_DELAY = 2  # リクエスト間の遅延は2秒
RANDOMIZE_DOWNLOAD_DELAY = True  # ランダムな遅延

# User-Agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'

# エラー時の再試行
RETRY_TIMES = 3
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 429]

ニューススクレイピング用のスパイダー

# news_spider.py

import scrapy
from datetime import datetime

class NewsSpider(scrapy.Spider):
    name = 'news_parser'
    
    # スクレイピングするニュースサイトのリスト
    start_urls = [
        'https://example-news.com/latest',
    ]
    
    def parse(self, response):
        # ホームページの記事リストをスクレイピング
        articles = response.css('article.news-item')
        
        for article in articles:
            article_url = article.css('a.title::attr(href)').get()
            
            if article_url:
                # 記事ページに移動
                yield response.follow(article_url, callback=self.parse_article)
    
    def parse_article(self, response):
        # 記事のデータを抽出
        yield {
            'url': response.url,
            'title': response.css('h1.article-title::text').get(),
            'date': response.css('time.published::attr(datetime)').get(),
            'author': response.css('span.author::text').get(),
            'text': ' '.join(response.css('div.article-body p::text').getall()),
            'tags': response.css('a.tag::text').getall(),
            'scraped_at': datetime.now().isoformat(),
        }

スクレイパーの実行

# JSONに保存
scrapy crawl news_parser -o news_data.json

# CSVに保存
scrapy crawl news_parser -o news_data.csv

requests + BeautifulSoupを使用したシンプルなスクレイパー

複雑なロジックが必要ない場合、requests + BeautifulSoupの組み合わせを使用できます:

import requests
from bs4 import BeautifulSoup
import time
import random

# プロキシの設定
proxies = {
    'http': 'http://user:pass@proxy.example.com:8080',
    'https': 'http://user:pass@proxy.example.com:8080'
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

def parse_news_article(url):
    try:
        response = requests.get(url, proxies=proxies, headers=headers, timeout=10)
        response.raise_for_status()
        
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # データの抽出(セレクタはサイトによって異なります)
        title = soup.find('h1', class_='article-title').text.strip()
        date = soup.find('time', class_='published')['datetime']
        text = ' '.join([p.text for p in soup.find_all('p', class_='article-text')])
        
        return {
            'url': url,
            'title': title,
            'date': date,
            'text': text
        }
    
    except Exception as e:
        print(f'Error parsing {url}: {e}')
        return None

# 記事リストのスクレイピング
urls = [
    'https://news-site.com/article-1',
    'https://news-site.com/article-2',
]

for url in urls:
    article_data = parse_news_article(url)
    if article_data:
        print(article_data)
    
    # リクエスト間の遅延
    time.sleep(random.uniform(2, 4))

ニューススクレイピングの一般的な間違い

プロキシの正しい設定があっても、スクレイパーは技術的なエラーのためにしばしばブロックされます。最も一般的な問題とその解決策を見ていきましょう。

エラー1:リクエストの頻度が高すぎる

症状:HTTP 429(Too Many Requests)、IPの一時的な禁止、CAPTCHA。原因:スクレイパーが1秒間に10-50リクエストを行うこと。解決策:遅延を追加してください(time.sleep())、ScrapyでDOWNLOAD_DELAYを使用し、CONCURRENT_REQUESTSを制限してください。

エラー2:すべてのリクエストに同じプロキシを使用する

症状:遅延があってもプロキシがすぐに禁止される。原因:1つのIPが1つのサイトに数百のリクエストを行うこと。解決策:ローテーションを持つプロキシプールを使用し、大規模なサイトには最低10-20のプロキシを使用し、スティッキーセッションの場合は10-15分ごとにIPを変更してください。

エラー3:クッキーを無視する

多くのニュースサイトは最初の訪問時にクッキーを設定し、次のリクエストでその存在を確認します。クッキーがないことはボットの兆候です。解決策:requests.Session()を使用してクッキーを自動的に保存し、ScrapyではCOOKIES_ENABLED = Trueを有効にしてください。

import requests

session = requests.Session()
session.proxies = {'http': 'http://proxy.com:8080', 'https': 'http://proxy.com:8080'}

# 最初のリクエスト — クッキーを取得
response1 = session.get('https://news-site.com')

# その後のリクエストは自動的にクッキーを送信
response2 = session.get('https://news-site.com/article')

エラー4:リダイレクトの不適切な処理

ニュースサイトは、モバイル版、地域のサブドメイン、AMPページのためにリダイレクト(301、302)を使用することがよくあります。スクレイパーがリダイレクトに従わない場合、空のページを取得します。解決策:requestsではデフォルトで有効(allow_redirects=True)、最終URLをresponse.urlで確認してください。

エラー5:JavaScriptなしで動的コンテンツをスクレイピングする

多くの現代のニュースサイトは、JavaScript(React、Vue)を介してコンテンツを読み込みます。requestsライブラリは、記事なしの空のHTMLスケルトンを取得します。解決策:Selenium/Playwrightを使用してJavaScriptを実行し、DevToolsのNetworkを確認してください — データがAPIを介して読み込まれている可能性があります(直接JSONをスクレイピングできます)。

スケーリング:数百のソースのスクレイピング

1つのニュースサイトではなく、同時に数百のソースをスクレイピングする必要がある場合(ニュースアグリゲーター、メディアモニタリング)、スケーラブルなアーキテクチャが必要です。

Scrapy Cloudによる分散スクレイピング

Scrapy Cloud(Scrapyの開発者による)は、クラウドでスクレイパーを実行し、自動的にスケーリングを行うことを可能にします。利点:自分のサーバーは不要、自動プロキシローテーション、モニタリングとログ。コスト:基本プランは月額$9から。

タスクキュー(Celery + Redis)

自分で展開する場合は、分散タスクシステムであるCeleryを使用します。アーキテクチャ:Redisがスクレイピング用のURLキューを保持し、複数のワーカー(サーバー)がキューからタスクを取得し、並行してスクレイピングを行います。各ワーカーは独自のプロキシプールを使用します。

# tasks.py

from celery import Celery
import requests

app = Celery('news_parser', broker='redis://localhost:6379/0')

@app.task
def parse_article(url, proxy):
    proxies = {'http': proxy, 'https': proxy}
    response = requests.get(url, proxies=proxies, timeout=10)
    # スクレイピングとデータの保存
    return response.text

# タスクをキューに追加
urls = ['https://news1.com/article', 'https://news2.com/article']
proxies = ['http://proxy1.com:8080', 'http://proxy2.com:8080']

for url in urls:
    proxy = random.choice(proxies)
    parse_article.delay(url, proxy)  # 非同期実行

モニタリングとエラーハンドリング

大規模なスクレイピングでは、モニタリングが非常に重要です:処理されたURLの数、エラーの数、禁止されたプロキシ。Pythonのエラーを追跡するためにSentryを使用し、メトリクス(リクエスト/秒、応答時間)にはGrafana + Prometheusを使用し、ELKスタック(Elasticsearch、Logstash、Kibana)でログを記録します。

アドバイス: プロキシの自動チェックシステムを作成してください。5-10分ごとに、各プロキシをwhoer.netまたはhttpbin.orgにテストリクエストを送信します。プロキシが応答しないか禁止されている場合は、プールから除外し、新しいものを追加します。

プロキシコストの最適化

数百のソースをスクレイピングする際、プロキシのコストは月に数千ドルに達することがあります。最適化戦略:簡単なサイト(RSS、API)にはデータセンターのプロキシを使用し、保護されたサイトにはレジデンシャルプロキシを使用し、データをキャッシュして同じ記事を二度スクレイピングしないようにし、ピーク時間外(夜間はサイトの負荷が低く、禁止のリスクが少ない)にスクレイピングしてください。

例:500のニュースサイトをスクレイピングする場合、80%のデータセンターのプロキシ(RSSや簡単なサイト用)と20%のレジデンシャルプロキシ(トップ100の保護されたポータル用)を使用できます。これにより、コストを3-5倍削減できます。

結論

ニュースサイトのスクレイピングは、プロキシの正しい選択、ローテーションの設定、アンチボットシステムの回避を必要とする技術的に難しいタスクです。この記事の重要な結論:保護されたニュースポータル(Cloudflare、厳しいレート制限)にはスティッキーセッションを持つレジデンシャルプロキシを使用し、大量のソースのスクレイピングには迅速なローテーションを持つデータセンターのプロキシを使用し、リクエスト間に遅延(2-5秒)と正しいHTTPヘッダーを必ず追加し、Cloudflareを回避するためにはヘッドレスブラウザ(Selenium、Playwright)やTLSフィンガープリンティングを持つライブラリを使用してください。

スケーリング時には、分散システム(Celery、Scrapy Cloud)とエラーモニタリングを使用してください。スクレイピングは倫理的であるべきことを忘れずに — robots.txtを遵守し、サーバーに過度の負荷をかけず、コンテンツに対する著作権を尊重してください。

Cloudflareの保護がある大規模なニュースポータルをスクレイピングする予定がある場合は、レジデンシャルプロキシの使用をお勧めします — 高い信頼性と最小限のブロックリスクを提供します。速度とデータ量が重要なタスク(RSS、APIエンドポイントのスクレイピング)には、データセンターのプロキシが適しています。

```