Trường Hợp Sử Dụng

Quét bảng công việc bằng cách xử lý CAPTCHA bằng CaptchaAI

Các trang tuyển dụng như Indeed, LinkedIn và Glassdoor triển khai CAPTCHA khi chúng phát hiện các mẫu truy cập tự động. Các nền tảng tuyển dụng, nhà nghiên cứu thị trường và công cụ phân tích nhân sự cần giải pháp CAPTCHA đáng tin cậy để thu thập dữ liệu danh sách việc làm trên quy mô lớn.


CAPTCHA trên các bảng việc làm chính

Nền tảng Loại CAPTCHA Trình kích hoạt Dữ liệu có sẵn
Quả thực reCAPTCHA v2 Khối lượng yêu cầu cao Danh sách việc làm, mức lương
LinkedIn Cloudflare Challenge Phát hiện bot Việc làm, dữ liệu công ty
cửa kính reCAPTCHA v2 Phát hiện cạo Đánh giá, lương, việc làm
ZipNhà tuyển dụng Cloudflare Turnstile Truy cập tự động Danh sách việc làm
Quái vật reCAPTCHA v2 Trang tìm kiếm Danh sách việc làm
Tuyển dụng reCAPTCHA v3 Đăng nhập, tìm kiếm Danh sách việc làm, tìm kiếm sơ yếu lý lịch

Trình quét bảng công việc có xử lý CAPTCHA

import requests
import time
import re
from bs4 import BeautifulSoup

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"

def solve_captcha(method, sitekey, pageurl, **kwargs):
    data = {
        "key": CAPTCHAAI_KEY,
        "method": method,
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }
    data.update(kwargs)
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        r = result.json()
        if r["request"] != "CAPCHA_NOT_READY":
            return r["request"]
    raise TimeoutError("Solve timeout")

class JobBoardScraper:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
            "Accept-Language": "en-US,en;q=0.9",
        })

    def search_jobs(self, base_url, query, location, pages=5):
        """Search job listings across multiple pages."""
        all_jobs = []

        for page in range(pages):
            url = f"{base_url}/jobs?q={query}&l={location}&start={page * 10}"
            resp = self.session.get(url, timeout=30)

            # Check for CAPTCHA
            if self._has_captcha(resp.text):
                resp = self._solve_and_retry(resp.text, url)

            if resp.status_code == 200:
                jobs = self._parse_listings(resp.text)
                all_jobs.extend(jobs)
                print(f"Page {page + 1}: {len(jobs)} jobs found")
            else:
                print(f"Page {page + 1}: Request failed ({resp.status_code})")

            time.sleep(3)  # Rate limit

        return all_jobs

    def _has_captcha(self, html):
        indicators = [
            'data-sitekey=',
            'g-recaptcha',
            'cf-turnstile',
            'captcha-delivery',
        ]
        return any(ind in html.lower() for ind in indicators)

    def _solve_and_retry(self, html, url):
        # Try reCAPTCHA first
        match = re.search(r'data-sitekey="([^"]+)"', html)
        if match:
            sitekey = match.group(1)

            # Detect Turnstile vs reCAPTCHA
            if 'cf-turnstile' in html:
                token = solve_captcha("turnstile", sitekey, url)
                field = "cf-turnstile-response"
            else:
                token = solve_captcha("userrecaptcha", sitekey, url)
                field = "g-recaptcha-response"

            return self.session.post(url, data={field: token})

        return self.session.get(url)

    def _parse_listings(self, html):
        soup = BeautifulSoup(html, "html.parser")
        jobs = []

        for card in soup.select(".job_seen_beacon, .jobsearch-ResultsList > li"):
            title_el = card.select_one("h2 a, .jobTitle a")
            company_el = card.select_one(".companyName, [data-testid='company-name']")
            location_el = card.select_one(".companyLocation, [data-testid='text-location']")
            salary_el = card.select_one(".salary-snippet, .estimated-salary")

            if title_el:
                jobs.append({
                    "title": title_el.get_text(strip=True),
                    "company": company_el.get_text(strip=True) if company_el else "",
                    "location": location_el.get_text(strip=True) if location_el else "",
                    "salary": salary_el.get_text(strip=True) if salary_el else "",
                    "url": title_el.get("href", ""),
                })

        return jobs

# Usage
scraper = JobBoardScraper(
    proxy="http://user:pass@residential.proxy.com:5000"
)
jobs = scraper.search_jobs(
    base_url="https://jobs.example.com",
    query="python developer",
    location="New York",
    pages=10,
)
print(f"Total jobs collected: {len(jobs)}")

Thu thập dữ liệu tiền lương

import csv

def collect_salary_data(titles, locations, output_file):
    """Collect salary data across job titles and locations."""
    scraper = JobBoardScraper(
        proxy="http://user:pass@residential.proxy.com:5000"
    )

    results = []
    for title in titles:
        for location in locations:
            try:
                jobs = scraper.search_jobs(
                    "https://jobs.example.com",
                    title, location, pages=3,
                )
                salaries = [j["salary"] for j in jobs if j["salary"]]
                results.append({
                    "title": title,
                    "location": location,
                    "listings": len(jobs),
                    "with_salary": len(salaries),
                    "salary_samples": "; ".join(salaries[:5]),
                })
                time.sleep(5)
            except Exception as e:
                results.append({
                    "title": title,
                    "location": location,
                    "error": str(e),
                })

    with open(output_file, "w", newline="") as f:
        writer = csv.DictWriter(
            f, fieldnames=["title", "location", "listings",
                           "with_salary", "salary_samples", "error"],
        )
        writer.writeheader()
        writer.writerows(results)

    return results

# Collect salary data for market analysis
collect_salary_data(
    titles=["Data Engineer", "ML Engineer", "DevOps Engineer"],
    locations=["San Francisco", "New York", "Austin", "Remote"],
    output_file="salary_data.csv",
)

Mẹo cấu hình lén lút cho bảng công việc

Kỹ thuật Tại sao nó giúp ích
đa dạng nguồn yêu cầu luân phiên Phân phối yêu cầu trên các IP thực
Độ trễ 3-5 giây giữa các trang Bắt chước tốc độ duyệt web của con người
Tác nhân người dùng nhất quán mỗi phiên Tránh dấu vân tay không khớp
Chấp nhận cookie Bảng công việc theo dõi các phiên thông qua cookie
Thứ tự tìm kiếm ngẫu nhiên Tránh các mẫu trang tuần tự
Giới hạn ở 200 trang/day cho mỗi tên miền Ở dưới ngưỡng phát hiện

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
CAPTCHA trên mọi tìm kiếm IP bị gắn cờ hoặc vượt quá tốc độ Chuyển đổi IP, thêm độ trễ dài hơn
Trang kết quả trống Thay vào đó, khối CAPTCHA được trả về Phát hiện CAPTCHA trước khi phân tích cú pháp
"Xin hãy xác minh bạn là con người" Đã kích hoạt tính năng phát hiện bot Sử dụng đa dạng nguồn yêu cầu + UA thực tế
Yêu cầu đăng nhập cho dữ liệu tiền lương Nội dung kiểm soát nền tảng Triển khai phiên xác thực
Kết quả khác với trình duyệt Vị trí/cookie sự khác biệt Phù hợp với ngôn ngữ chấp nhận và proxy địa lý

Câu hỏi thường gặp

Tôi có thể thu thập bao nhiêu danh sách việc làm mỗi ngày?

Với các proxy dân dụng luân phiên và độ trễ thích hợp, có thể đạt được 500-2000 trang cho mỗi tên miền mà không cần phải gặp CAPTCHA liên tục.

Bảng công việc có chặn việc cạo không?

Hầu hết các bảng việc làm đều có các điều khoản không khuyến khích truy cập tự động nhưng có cách thực thi khác nhau. CAPTCHA là biện pháp bảo vệ chính của chúng, được CaptchaAI xử lý.

Loại proxy nào hoạt động tốt nhất cho bảng công việc?

Các ủy quyền dân cư luân phiên là sự cân bằng tốt nhất giữa chi phí và tỷ lệ thành công. IP của trung tâm dữ liệu thường xuyên bị LinkedIn và Glassdoor chặn.


Hướng dẫn liên quan


Thu thập dữ liệu thị trường việc làm trên quy mô lớn —lấy khóa CaptchaAI của bạnđể giải CAPTCHA tự động.

Os comentários estão desativados para este artigo.