Q&A
前提
Python+Selenium+Torを使って、データ収集目的で、とあるサイトのスクレイピングのプログラムを実装しています。
画面のボタン押下イベントにより、表示が切り替わるページのため、Seleniumが必須なサイトです。
全部で3,000件ほどの詳細ページの情報を取得したいのですが、途中までは想定通りに動くものの、
約100件目程に差し掛かると、403エラーが表示され接続できなくなります。
↓driver.page_source
の結果
html
1<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n<p>You don't have permission to access /buy/search/detail/\non this server.</p>\n\n</body></html>
腑に落ちない点としては、
Torプロキシを介しての接続のため、Tor再起動するとIPアドレスが変わって、接続できるかと思いましたが、
IPを変更しても改善されず、更に加えて、通常のChromeブラウザでの該当URLへのアクセスも拒否されるようになり、突破口を見いだせない状況で質問させて頂いた次第です。
※Bot対策を行なっているサイトに、過度なクローリングは控えなければならないことは重々承知しております🙇♂️
実現したいこと
- アクセス制限を受けず、安定的にクローリングが行える状態を実現したい
発生している問題・エラーメッセージ
Seleniumでアクセスした場合
Bad Request Your browser sent a request that this server could not understand.
通常のChromeブラウザからアクセスした場合
Forbidden You don't have permission to access /buy/ on this server.
該当のソースコード
python
1 2 3# メイン処理 4DOMAIN = "https://www.janpara.co.jp/" 5START_URL = "https://www.janpara.co.jp/buy/search/result/?KEYWORDS=&OUTCLSCODE=46&CLSCODE=&LINE=24" 6PROXY = 'localhost:9050' 7 8if __name__ == '__main__': 9 10 options = webdriver.chrome.options.Options() 11 options.add_argument(f'--proxy-server=socks5://{PROXY}') 12 chrome_service = fs.Service(executable_path="/Users/nakazono/Downloads/chromedriver") 13 driver = webdriver.Chrome(service=chrome_service, options=options) 14 driver.implicitly_wait(3) 15 16 nextlink = None 17 i= 0 18 results = [] 19 20 while True: 21 i += 1 22 logger.info(f"{i}ページ目===========================================================================") 23 24 driver.get(nextlink or START_URL) 25 soup = BeautifulSoup(driver.page_source, 'html.parser') 26 detail_urls = get_detail_urls(soup) 27 28 for detail_url in detail_urls: 29 try: 30 # ここで要素の情報を取得する 31 32 except Exception as e: 33 print(e) 34 continue 35 36 # 次ページへ 37 nextlink = get_nextlink("/buy/search/result/" ,soup) 38 if not nextlink: 39 break 40 41class TorControlPortClient: 42 control_address: str 43 control_port: int 44 control_password: Optional[str] 45 46 def __init__( 47 self, 48 control_address: str, 49 control_port: int, 50 control_password: Optional[str] = None 51 ): 52 self.control_address = control_address 53 self.control_port = control_port 54 self.control_password = control_password 55 56 def change_connection_ip(self, seconds_wait: int = 5) -> bool: 57 time.sleep(seconds_wait) 58 try: 59 tor_connection = socket.create_connection((self.control_address, self.control_port)) 60 password_value = self.control_password if self.control_password is not None else '' 61 message = f'AUTHENTICATE "{password_value}"\r\nSIGNAL NEWNYM\r\n' 62 tor_connection.send(message.encode('utf-8')) 63 response = tor_connection.recv(1024) 64 if response != b'250 OK\r\n250 OK\r\n': 65 sys.stderr.write('Unexpected response from Tor control port: {}\n'.format(response)) 66 return False 67 return True 68 except Exception as e: 69 print(e) 70 sys.stderr.write('Error connecting to Tor control port: {}\n'.format(repr(e))) 71 return False 72 73@retry(wait=wait_exponential(multiplier=1, min=3, max=50)) 74def get_html(url): 75 """ 76 HTTPリクエストしてBeautifulSoupオブジェクトに変換する 77 """ 78 headers = { 79 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36" 80 } 81 82 proxies = { 83 'http': 'socks5://localhost:9050', 84 'https': 'socks5://localhost:9050', 85 } 86 87 time.sleep(2) 88 89 res = requests.get(url, headers=headers, proxies=proxies) 90 print(res.content) 91 if 300 <= res.status_code <= 599: 92 tor_control_port_client = TorControlPortClient('localhost', 9051, 'test1234') 93 tor_control_port_client.change_connection_ip(seconds_wait=3) 94 print("IP Address is Changed") 95 raise Exception("IPチェンジ!!!") 96 97 soup = BeautifulSoup(res.content, 'html.parser') 98 return soup 99 100def get_detail_urls(soup): 101 items = soup.select(".search_item > h3 > a[href]") 102 for item in items: 103 yield item.get("href") 104 105def get_nextlink(path, soup): 106 try: 107 nextlink = DOMAIN + path + soup.select_one(".pageLink[title='次ページ']").get("href") 108 except Exception as e: 109 print("Last Page") 110 nextlink = None 111 112 return nextlink 113
試したこと
- Torが機能しているか IPアドレス確認サイトで確認した
headless
,no-sandbox
オプションなどを付与してみたが結果は変わらなかった- ネットの接続回線とプロキシの有無を切り替えると結果は以下となった。
回線 | プロキシ | 結果 |
---|---|---|
Wifi | 有 | × |
Wifi | 無 | × |
テザリング | 有 | × |
テザリング | 無 | ○ |
補足情報(FW/ツールのバージョンなど)
- python3.8
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2022/11/02 01:35