curl_cffi
curl_cffi
는 파이썬에서 고성능 HTTP 요청을 수행하기 위해 설계된 라이브러리이다.
보통 파이썬으로 데이터를 스크래핑할 때 requests
나 httpx
를 자주 사용하는데,
curl_cffi
는 위 두 라이브러리와 달리 브라우저의 TLS 서명이나 JA3 지문을 모방할 수 있다고 한다.
만약 requests
나 httpx
를 사용하여 스크래핑을 시도했을 때, 특별한 이유 없이 바로 차단이 된다면 curl_cffi
를 사용해보는 것을 추천한다.
curl_cffi
의 특징은 다음과 같다.
- JA3/TLS, http2 fingerprints 모방 지원
requests
,httpx
보다 빠름requests
라이브러리의 API들을 모방하여 기존 프로젝트에서 쉽게 전환가능
설치 방법
pip install curl_cffi
사용 방법
위에서 말했듯이 requests
의 API들을 모방하였기에 requests
를 쓰듯이 사용하면 되지만, 조금씩 다른 점은 있다.
from curl_cffi import requests as rq
url: str = "https://example.com/"
response = rq.get(url=url, impersonate="chrome110")
print(r.text)
impersonate
: 특정 브라우저(chrome, firefox ..)와 동일한 방식으로 HTTP 요청을 보내는 기능- Chrome:
chrome99
,chrome100
, ...chrome110
- Firefox:
firefox99
,firefox100
...firefox110
- Chrome:
Proxy를 쓰려면 다음과 같이 작성하면 된다.
from curl_cffi import requests as rq
url: str = "https://example.com/"
proxies: list[str] = [
"https": "http://localhost:4444"
]
response = rq.get(url=url, impersonate="chrome110")
print(r.text)
Session
객체를 생성할 수도 있다.
from curl_cffi import requests as rq
url: str = "https://example.com/"
s = rq.Session()
s.get(url=url)
print(s.cookies)
print(s.cookies.get_dict())
r = s.get(url=url)
print(r.json())
라이브러리 비교
스크래핑을 자주하는 사람들이라면 사이트에서 요청되는 header
나 cookie
값을 추출하는 방법에 대해서 알고있을거다.
사이트에서 크롤링을 어떤 식으로 막느냐에 따라, 필요한 정보들이 달라지는데(User-Agent
, referer
, Cookie
값 등등)
문제는 서버를 속이기 위해 위 정보들을 감쪽같이 맞춰도 파훼가 되지 않는 경우가 있다는 것이다.
확실한 비교를 위해 클라우드 플레어의 HTML
정보를 가져오는 것을 목표로 코드를 작성해보자.
헤더 값은 해당 사이트를 들어갔을 때 요청되는 패킷을 그대로 복사 & 붙여넣기 한다.
from bs4 import BeautifulSoup as bs
import requests as rq
url: str = "https://www.cloudflare.com/ko-kr/lp/ppc/overview-x/"
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "ko,en;q=0.9,en-US;q=0.8",
"cache-control": "max-age=0",
"priority": "u=0, i",
"referer": "https://velog.io/",
"sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "cross-site",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"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 Edg/131.0.0.0",
}
response = rq.get(url=url, headers=headers)
soup = bs(response.text, "html.parser")
with open("test-requests.html", "w", encoding="utf-8") as fp:
fp.write(soup.prettify())
뭔가 잘못된 것이 보이는가? 정상적으로 데이터 추출이 되지 않는 상황이다.
그렇다면, 지금 이 상황에서 requests
가 아닌 curl_cffi
를 사용해본다면 어떨까?
from bs4 import BeautifulSoup as bs
from curl_cffi import requests as rq
url: str = "https://www.cloudflare.com/ko-kr/lp/ppc/overview-x/"
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "ko,en;q=0.9,en-US;q=0.8",
"cache-control": "max-age=0",
"priority": "u=0, i",
"referer": "https://velog.io/",
"sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "cross-site",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"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 Edg/131.0.0.0",
}
response = rq.get(url=url, headers=headers)
soup = bs(response.text, "html.parser")
with open("test-requests.html", "w", encoding="utf-8") as fp:
fp.write(soup.prettify())
뭐가 바뀌었는지 감이 오는가? 전체 HTML 파일을 정상적으로 추출한 것을 볼 수 있다.
마무리
사이트의 크롤링 차단 구조에 따라서 requests
, httpx
, curl_cffi
를 적절하게 사용해보는 것이 좋을 것 같다.
그래도 안된다면 어쩔 수 없이 셀레니움 rr