안티봇 우회용 브라우저 프로필 추가

feature-imageMatch
김성경 2026-07-09 15:20:29 +09:00
parent 2107d5adf1
commit e6764a85bd
1 changed files with 41 additions and 12 deletions

View File

@ -1,4 +1,5 @@
import asyncio import asyncio
import random
import re import re
from html import unescape from html import unescape
from difflib import SequenceMatcher from difflib import SequenceMatcher
@ -21,27 +22,55 @@ class NvMapPwScraper():
_max_retry = 3 _max_retry = 3
_timeout = 30 # place id timeout threshold seconds _timeout = 30 # place id timeout threshold seconds
_retry_delay_ms = 1500 # 검색 실패 후 재시도 전 대기시간 (네이버 요청 밀도 완화) _retry_delay_ms = 1500 # 검색 실패 후 재시도 전 대기시간 (네이버 요청 밀도 완화)
# UA·뷰포트·sec-ch-ua를 한 세트로 묶은 브라우저 프로필 후보군 (안티봇 핑거프린트 회피용)
_UA_PROFILES = [
{
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
"sec_ch_ua": '"Not?A_Brand";v="99", "Chromium";v="130", "Google Chrome";v="130"',
"viewport": {"width": 1280, "height": 720},
},
{
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
"sec_ch_ua": '"Not?A_Brand";v="99", "Chromium";v="129", "Google Chrome";v="129"',
"viewport": {"width": 1366, "height": 768},
},
{
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
"sec_ch_ua": '"Not?A_Brand";v="99", "Chromium";v="130", "Google Chrome";v="130"',
"viewport": {"width": 1440, "height": 900},
},
{
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"sec_ch_ua": '"Not?A_Brand";v="99", "Chromium";v="131", "Google Chrome";v="131"',
"viewport": {"width": 1536, "height": 864},
},
]
_current_profile = None
# instance var # instance var
page = None page = None
@classmethod
def _pick_profile(cls):
"""현재 프로필과 다른 프로필을 무작위로 선택한다 (후보가 1개뿐이면 그대로 반환)."""
candidates = [p for p in cls._UA_PROFILES if p is not cls._current_profile]
return random.choice(candidates or cls._UA_PROFILES)
@classmethod @classmethod
def default_context_builder(cls): def default_context_builder(cls):
cls._current_profile = cls._pick_profile()
profile = cls._current_profile
context_builder_dict = {} context_builder_dict = {}
context_builder_dict['viewport'] = { context_builder_dict['viewport'] = dict(profile['viewport'])
'width' : cls._win_width, context_builder_dict['screen'] = dict(profile['viewport'])
'height' : cls._win_height context_builder_dict['user_agent'] = profile['user_agent']
}
context_builder_dict['screen'] = {
'width' : cls._win_width,
'height' : cls._win_height
}
context_builder_dict['user_agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
context_builder_dict['locale'] = 'ko-KR' context_builder_dict['locale'] = 'ko-KR'
context_builder_dict['timezone_id']='Asia/Seoul' context_builder_dict['timezone_id']='Asia/Seoul'
return context_builder_dict return context_builder_dict
@classmethod @classmethod
async def initiate_scraper(cls): async def initiate_scraper(cls):
if not cls._playwright: if not cls._playwright:
@ -203,7 +232,7 @@ patchedGetter.apply(navigator);
patchedGetter.toString();''') patchedGetter.toString();''')
await self.page.set_extra_http_headers({ await self.page.set_extra_http_headers({
'sec-ch-ua': '\"Not?A_Brand\";v=\"99\", \"Chromium\";v=\"130\"' 'sec-ch-ua': self._current_profile['sec_ch_ua']
}) })
await self.page.goto("http://google.com") await self.page.goto("http://google.com")