본문 바로가기
Coders tool/python

[Python] proxy를 이용한 웹스크래핑 차단 방지 방법

by Code Wizard 2023. 7. 13.

1. [Python] proxy를 이용한 웹스크래핑 차단 방지 방법 이 필요한 이유

Python을 이용한 웹 스크래핑은 인터넷에서 정보를 수집하는 강력한 도구입니다. 그러나 많은 웹 사이트들은 스크래핑을 방지하기 위해 차단 메커니즘을 갖추고 있습니다. 이러한 차단을 우회하고 원하는 데이터를 스크래핑하기 위해서는 프록시를 활용할 수 있습니다. 이번 글에서는 Python을 사용하여 웹 스크래핑 차단을 우회하는 방법에 대해 알아보겠습니다.

2. Proxy 사용 방법

가장 기본적인 방법은 프록시 서버를 사용하는 것입니다. 프록시 서버는 클라이언트와 웹 사이트 간의 중간자 역할을 수행하여 실제 IP 주소를 숨기고 요청을 전달합니다. Python에서는 requests 라이브러리를 사용하여 프록시 서버를 설정할 수 있습니다. 예를 들어, 다음과 같은 코드를 사용하여 프록시 서버를 설정할 수 있습니다.

import requests

proxy = {
    'http': 'http://proxy_server_ip:proxy_server_port',
    'https': 'https://proxy_server_ip:proxy_server_port'
}

response = requests.get(url, proxies=proxy)

또한 웹 사이트는 일반적으로 User-Agent 헤더를 통해 브라우저 정보를 확인합니다. 스크래핑 봇은 일반적으로 표준 브라우저와 다른 User-Agent를 가지고 있기 때문에 차단될 수 있습니다. User-Agent 헤더를 조작하여 스크래핑하는 동안 일반 사용자인 것처럼 보이도록 설정할 수 있습니다. Python의 requests 라이브러리에서는 headers 매개변수를 사용하여 User-Agent 헤더를 설정할 수 있습니다. 예를 들어 다음과 같이 설정할수 있습니다.

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}

response = requests.get(url, headers=headers)

위 두가지 설정을 합쳐서 설정하면 다음과 같습니다.

 

import requests

proxy = {
    'http': 'http://proxy_server_ip:proxy_server_port',
    'https': 'https://proxy_server_ip:proxy_server_port'
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}

response = requests.get(url, proxies=proxy, headers=headers)

3. Proxy IP 회전 방법

일부 웹 사이트는 단일 IP 주소에서의 과도한 요청을 감지하고 차단합니다. 이를 우회하기 위해 IP 주소를 회전시키는 방법을 사용할 수 있습니다. Python에서는 다양한 프록시 서비스를 통해 회전 IP 주소를 얻을 수 있습니다. 예를 들어, "Scrapingant"나 "Scraperapi"와 같은 서비스를 사용하여 IP 주소를 동적으로 변경할 수 있습니다. 이렇게 하면 단일 IP 주소로 인한 차단을 피할 수 있습니다.

 

4. Proxy IP 회전 제공 사이트 소개

IP를 회전시켜서 제공하는 사이트가 많이 있습니다. GB단위로 요금을 내는 사이트와 API단위로 요금을 내는 사이트가 있고 동시요청을 제한하는 곳도 있습니다.

  • Scraperapi
    • 비동기 서비스 지원
    • 아마존 및 구글 API 별도 제공.
    • 웹브라우저에서 사용 불가 (비동기 방식이므로)
    • 요금제에 따라 동시성 제공 한계 있음 (20개, 50개 등)
    • 최저요금 : 월 49$ / 10만 API 크레딧 제공
  • Scrapingant
    • 동기 서비스
    • 아마존등의 별도 API 없음
    • 웹브라우저에서 사용가능
    • 동시성 제한 없음.
    • 최저요금 : 월 19$ / 10만 API 크래딧
    • Enthusiast 요금제 50% 할인코드 : ENTHUSIAST_50

아래는 각 사이트별 사용 방법입니다.

  • scraperapi 사이트

다량 사이트 요청 

import requests

r = requests.post(url = 'https://async.scraperapi.com/batchjobs', json={ 'apiKey': 'xxxxxx', 'urls': ['https://example.com/page1', 'https://example.com/page2' ]})
print(r.text)

응답 

[
		{
"id":"0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"status":"running",
"statusUrl":"https://async.scraperapi.com/jobs/0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"url":"https://example.com/page1"
}
{
"id":"238d54a1-62af-41a9-b0b4-63f240bad439",
"status":"running",
"statusUrl":"https://async.scraperapi.com/jobs/238d54a1-62af-41a9-b0b4-63f240bad439",
"url":"https://example.com/page2"
}
]

위에서 받은 statusUrl을 호출하여 status값이 finished로 오면 작업을 하면 됩니다.

import requests

r = requests.get(url = 'https://async.scraperapi.com/jobs/0962a8e0-5f1a-4e14-bf8c-5efcc18f0953')
print(r.text)

#작업중 응답

{
"id":"0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"status":"running",
"statusUrl":"https://async.scraperapi.com/jobs/0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"url":"https://example.com"
}

#작업완료 응답

{
"id":"0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"status":"finished",
"statusUrl":"https://async.scraperapi.com/jobs/0962a8e0-5f1a-4e14-bf8c-5efcc18f0953",
"url":"https://example.com",
"response":{
"headers":{
"date":"Thu, 14 Apr 2022 11:10:44 GMT",
"content-type":"text/html; charset=utf-8",
"content-length":"1256",
"connection":"close",
"x-powered-by":"Express",
"access-control-allow-origin":"undefined","access-control-allow-headers":"Origin, X-Requested-With, Content-Type, Accept",
"access-control-allow-methods":"HEAD,GET,POST,DELETE,OPTIONS,PUT",
"access-control-allow-credentials":"true",
"x-robots-tag":"none",
"sa-final-url":"https://example.com/",
"sa-statuscode":"200",
"etag":"W/\"4e8-Sjzo7hHgkd15I/TYxuW15B7HwEc\"",
"vary":"Accept-Encoding"
},
"body":"<!doctype html>\n<html>\n<head>\n	<title>Example Domain</title>\n\n	<meta charset=\"utf-8\" />\n	<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n	<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n	<style type=\"text/css\">\n	body {\n		background-color: #f0f0f2;\n		margin: 0;\n		padding: 0;\n		font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n		\n	}\n	div {\n		width: 600px;\n		margin: 5em auto;\n		padding: 2em;\n		background-color: #fdfdff;\n		border-radius: 0.5em;\n		box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n	}\n	a:link, a:visited {\n		color: #38488f;\n		text-decoration: none;\n	}\n	@media (max-width: 700px) {\n		div {\n			margin: 0 auto;\n			width: auto;\n		}\n	}\n	</style>	\n</head>\n\n<body>\n<div>\n	<h1>Example Domain</h1>\n	<p>This domain is for use in illustrative examples in documents. You may use this\n	domain in literature without prior coordination or asking for permission.</p>\n	<p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
"statusCode":200
}
}

배치 요청으로 요청을 하고 쓰레드 방식으로 리턴값을 확인하여 처리를 하면 굉장히 빠르게 스크래핑 가능합니다.

 

  • scrapingant 사이트

동기 방식으로 아래와 같이 사용할수 있습니다.

결과를 받기까지 시간이 걸리므로 적절히 타임을 걸어서 사용하면 됩니다.

from urllib.parse import quote
import requests

        encoded_url = quote(siteUrl)
		apiKey = userKey

        proxyUrl = f'https://api.scrapingant.com/v2/general?url={encoded_url}&x-api-key={apiKey}&browser=false'
        
        r = requests.get(url = proxyUrl)

위 소스에 쓰레드를 얻어서 호출하면 마찬가지로 다량의 사이트를 동시에 스크래핑 가능합니다.

그리고 위 사이트는 아래와 같이 사용하면 브라우저에서 제어가 가능하게 됩니다.

from urllib.parse import quote
from playwright.sync_api import sync_playwright

with sync_playwright() as playwright:
	browser = playwright.chromium.launch()
	context = browser.new_context()
	page = context.new_page()
	encoded_url = quote(siteUrl)
	apiKey = userKey
	proxyUrl = f'https://api.scrapingant.com/v2/general?url={encoded_url}&x-api-key={apiKey}&browser=false'

    
	# 웹 페이지 열기
	page.goto(proxyUrl)
    
	# 스크린샷 캡처
	page.screenshot(path='screenshot.png')
    
	# 브라우저 종료
	context.close()
	browser.close()

5. 결론

Python에서 Proxy를 이용한 웹 스크래핑 차단 방지 방법을 소개했습니다. 프록시 서버를 사용하고 User-Agent 헤더를 설정하며 IP 주소를 회전시키는 방법을 활용하면 웹 스크래핑을 좀 더 원활하게 수행할 수 있습니다. 그러나 항상 웹 사이트의 이용 약관을 준수하고, 서비스 제공자의 정책을 확인하는 것이 중요합니다. 이러한 방법들을 적절하게 사용하여 윤리적이고 책임 있는 웹 스크래핑을 수행하시기 바랍니다.

 

위 사이트 링크를 통해서 가입시 작성자에게 일부 수익이 발생될수 있습니다.