이더리움 ERC-20 토큰 관련해서 DB화를 시켜야할일이 생겼었다.
토큰 정보들을 어디서 가져오기 고민하다가 그냥 심플하게 이더스캔에서 크롤링을 해오기로 결정.
위 페이지 내에서 토큰명, 심볼, contract address, 현재가격을 가져와서 저장하는 코드를 짠 뒤
실서버에 파일만 올려두고 크론탭을 이용해 주기적으로 실행시켜줄 생각이였다.
로컬에서 테스트를 마치고 리눅스서버에 올려서 테스트를 해보는데 오잉...?
잘 되던 소스가 안돌아간다...?
왜 element를 못찾나 싶어서 전체소스를 print해봤는데 서버에서 호출했더니
Cloudflare 방화벽에 막혀서 이더스캔이 아닌 Cloudflare 페이지가 떠서 크롤링을 못했던거였다.
Cloudflare recaptcha를 우회할 방법을 여기저기 찾아보고 일주일을 삽질하다가
역시 우리의 선생님 stackover flow에서 방법을 찾아서 여기 적어두려고 한다.
우선 pip로 selenium-stealth를 설치해주자.
pip install selenium-stealth
나머지는 그냥 코드로 보자..^^!
import requests
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium_stealth import stealth
# 이더스캔 토큰정보 크롤링 함수
def crawling_init():
result = []
# 환율정보
EXCHANGE_API_URL = 'https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD'
# 이더스캔 URL
EHTERSCAN_URL = 'https://etherscan.io'
response = requests.get(url=EXCHANGE_API_URL)
# 달러 -> 원화 환율기준
usd_to_krw = response.json()[0].get('basePrice')
options = webdriver.ChromeOptions()
# 크롬드라이버 헤더 옵션추가 (리눅스에서 실행시 필수)
options.add_argument("start-maximized")
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
# 크롬드라이버 경로
driver_path = '서버내의 크롬드라이버 경로'
driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)
### 추가된 부분 ###
# selenium stealth 옵션추가 ( cloudflare 우회용 )
stealth(driver,
languages=["en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
### // 추가된 부분 ###
driver.get(EHTERSCAN_URL + '/tokens?ps=50p=1')
driver.implicitly_wait(10)
# 전체 페이지 수
total_page = int(driver.find_element(By.XPATH,
'//*[@id="ContentPlaceHolder1_divpagingpanel"]/nav/ul/li[3]/span/strong[2]').text)
page_cnt = 1
while page_cnt < total_page + 1:
driver.get(EHTERSCAN_URL + '/tokens?p=' + str(page_cnt))
# 페이지 로딩 대기
driver.implicitly_wait(10)
# 토큰 리스트
token_xpath = '//*[@id="tblResult"]/tbody/tr'
token_td = driver.find_elements(By.XPATH, token_xpath)
token_td_len = len(token_td)
i = 1
while i < token_td_len + 1:
token_tr_xpath = token_xpath + '[' + str(i) + ']'
token_txt = driver.find_element(By.XPATH, token_tr_xpath + '/td[2]/div/div/h3/a').text
# 토큰명
token_name = token_txt.split(' (')[0]
# 토큰 심볼
token_symbol = token_txt.split(' (')[1].replace(')', '')
# 토큰 이미지 url
token_img = driver.find_element(By.XPATH, '//*[@id="tblResult"]/tbody/tr['
+ str(i) + ']/td[2]/div/img').get_attribute('src')
# 토큰 컨트랙트주소
contract_addr = \
driver.find_element(By.XPATH, token_tr_xpath + '/td[2]/div/div/h3/a').get_attribute('href').split(
'token/')[
1]
token_usd_price_txt = driver.find_element(By.XPATH, token_tr_xpath + '/td[3]').text
# 달러기준 가격
token_usd_price = token_usd_price_txt.split('\n')[0].replace('$', '').replace(',', '')
# 원화기준 가격
token_krw_price = round(float(token_usd_price) * usd_to_krw, 2)
obj = {'token_name': token_name, 'token_symbol': token_symbol, 'contract_addr': contract_addr,
'token_img': token_img, 'usd_price': token_usd_price, 'krw_price': token_krw_price}
result.append(obj)
i = i + 1
page_cnt = page_cnt + 1
driver.quit()
return result
기존 소스에 stealth 옵션을 추가해주면 끝..!
저게 막히면 또 무슨방법으로 해야될지는 모르겠다😢
* 참조
'Python' 카테고리의 다른 글
[Python] Twilio를 이용한 모바일 Voip 서비스 만들기 (1) | 2022.01.04 |
---|---|
[Python] pandas를 이용하여 엑셀 데이터 뽑기 (0) | 2021.11.19 |
[Python] 오픈 API를 이용해 공휴일 정보 받아오기 (0) | 2021.07.22 |
[Python] 셀레니움(Selenium)을 이용한 브라우저 동적 크롤링 (0) | 2020.12.16 |