Trouble Shooting

[Errno 110] Connection timed out - proxy 설정하기(해결)

hzoooo 2021. 11. 17. 02:41

공모주 알리미 기능 업데이트를 위해, 38커뮤니케이션 크롤링 코드를 실컷 짜고 로컬에서도 테스트를 마쳤다.

기분 좋게 heroku에 deploy 하고 코드를 실행하니 웬걸, 안된다.

 

로컬에서는 문제없이 38커뮤니케이션에 get 방식으로 html 코드를 얻어올 수 있었는데,

heroku 서버에서는 계속 못 받아오는 상황이 생겨서 4일째 해결방안을 찾고 있다.

크롤링하려는 url은, http://www.38.co.kr/html/fund/index.htm?o=k 이다.

 

로컬에서는 되는데 서버에서만 안되니까 너무 짜증이 난다..... 휴..😰

heroku server ip가 38 커뮤니티 측 화이트 리스트에 존재하지 않아서, 즉 ip 문제라고 여러 번의 구글링 결과가 말해 줬다.

 

아래 질문에서 나랑 똑같은 문제를 겪는데,

문제 원인이 'It sounds like the destination blocks Heroku’s IP(s)'라고 예상하고,

질문자가 위 대답을 받고 휴대폰의 Tasker을 이용하여 HTTP Request를 만들어서 해결했으며

'Just thought i'd leave my solution behind'라고 해서 어디에 solution을 적어둔 것 같은데.. 찾을 수가 없다.😬😬😬😬😬😬

 

해결하고 해결 완료로 빨리 바꾸고 싶다. 제발

EDIT : 오류 코드들 아래에 해결책을 적어두었다.

 

아래는 오류코드들이다. 3가지 중 하나는 될 줄 알았는데 근본적인 문제가 ip이니 당연히 될 리가 없던 일이었다..

 

https://www.reddit.com/r/Heroku/comments/k1e0dx/python_code_making_an_api_request_works_fine_on/

 

Python code making an API request works fine on my PC, but throws a "Connection Timed Out" error on Heroku. What am I doing wron

import requests import time headers = { 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control':...

www.reddit.com

 

1. requests 라이브러리 사용

[1-1. parameter 없이 request]

response = requests.get(url)
html = response.content.decode('euc-kr', 'replace')
self.soup = BeautifulSoup(html, 'lxml')

[1-2. headers에 일반 Mozilla/5.0 입력하여 request]

response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
html = response.content.decode('euc-kr', 'replace')
self.soup = BeautifulSoup(html, 'lxml')

[1-3. headers에 http://useragentstring.com/ 에서 얻은 로컬 user-agent 입력하여 request]

response = requests.get(url, headers={'User-Agent': os.environ.get('LOCAL_USER_AGENT')})
html = response.content.decode('euc-kr', 'replace')
self.soup = BeautifulSoup(html, 'lxml')

오류코드

Failed to establish a new connection: [Errno 110] Connection timed out


2. urllib.request 모듈 사용

with urllib.request.urlopen(url) as response:
	html = response.read().decode('euc-kr', 'replace')
self.soup = BeautifulSoup(html, 'lxml')

오류코드

urllib.error.URLError: <urlopen error [Errno 110] Connection timed out>


3. selenium webdriver 사용

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")

driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"),
chrome_options=chrome_options)
driver.implicitly_wait(10)
driver.get(url)
html = driver.page_source
driver.close()

오류코드

selenium.common.exceptions.WebDriverException: Message: unknown error: net::ERR_CONNECTION_TIMED_OUT

 


[21/11/17 수, 15:37]

글 쓴 지 하루도 안돼서 해결하니까 블로그 포스팅을 열심히 하라는 신의 계시인가도 싶고..

 

물론 다른 개발자들은 당연하게 바로 찾았을 수도 있겠지만, 역시 IP 문제였고 나는 위에서 말한 tasker는 뭔가 생소해서 일단 패스했다.

좀 더 크롤링을 해본 결과, proxy를 설정해서 request를 날리는 방법이 있어서 시도해봤는데 해결되었다.

위키백과에서 프록시가 뭔지 찾아보니, '서버와 클라이언트 사이에 중계기로써 대리로 통신을 수행하는 것, 즉 중계 기능을 하는 것'이라고 나와있어서, 차단된 ip가 아닌 프록시를 통해서 38커뮤니케이션에 request를 날릴 수 있게 됐구나, 정도로 이해하였다.

 

코드 아래에 있는 두 사이트는 무료 프록시이고, 나는 첫 번째 url에서 프록시를 얻었다.

한국 사이트이기에 한국 프록시로 찾았으며 80 포트 프록시를 찾은 이유는 full 에러코드에서 보이듯이,

request를 날릴 때 80 포트로 Connection을 시도하는 것 같아서 80 포트 프록시를 찾았다.

 

- Full Error Code

urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='www.38.co.kr', port=80): Max retries exceeded with url: /html/fund/index.htm?o=k (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x--------->: Failed to establish a new connection: [Errno 110] Connection timed out'))

 

proxy_url = 'https://free-proxy-list.net/'
proxy_res = requests.get(proxy_url)
proxy_html = proxy_res.content.decode('utf-8', 'replace')
soup = BeautifulSoup(proxy_html, 'lxml')
tbody = soup.select('table[class="table table-striped table-bordered"]')[0].contents[1]
rows = tbody.find_all('tr')
country = 'Korea'
port = '80'

for row in rows:
    tds =  row.find_all('td')
    if tds[3].text == country and tds[1].text == port:
        free_proxy = tds[0].text
        proxy = {"https": free_proxy, "http": free_proxy}
        try:
            response = requests.get(url, proxies=proxy)
            print(f'response : {proxy_res.status_code}')
            html = response.content.decode('euc-kr', 'replace')
            self.soup = BeautifulSoup(html, 'lxml')
            break
        except Exception as e:
            print(f'error occurred : {e}')

 

https://free-proxy-list.net/

 

Free Proxy List - Just Checked Proxy List

Free proxies from free-proxy-list.net Updated at 2021-11-17 06:32:04 UTC. 110.44.124.220:55443 176.118.209.12:53281 45.6.159.235:34523 182.52.236.134:8080 23.107.176.65:32180 103.79.155.42:46977 179.184.165.181:8080 36.95.156.127:6969 123.63.201.223:80 158

free-proxy-list.net

https://spys.one/free-proxy-list/KR/

 

Free South Korea proxy servers. Korean proxy - KR.

 

spys.one

 

공모주 알리미 개발하면서 이번 문제가 별거 아닌 문제에 발목 잡혔다고 생각했는데, 아직 초보 개발자라 본질적인 해결법을 몰라서 오래 걸린 것 같다.

오래 걸린 만큼, 해결한 후 후련함은 배가 됐다.

 

이래서 삽질하는 맛이 좋다.