HOOOS

豆瓣电影数据高效爬取指南:反爬策略与IP防封技巧

0 5 爬虫老司机 豆瓣爬虫反爬策略IP防封
Apple

豆瓣的反爬虫机制确实比较严格,直接硬刚很容易被封 IP。但别慌,作为一名老爬虫,我来分享一些经验,教你如何更高效、更安全地爬取豆瓣电影数据,同时尽量避免被封 IP。

一、了解豆瓣的反爬机制

在开始之前,我们需要先了解豆瓣常见的反爬虫手段,才能更好地制定应对策略:

  1. User-Agent 检测: 检查请求头的 User-Agent 字段,如果不是常见的浏览器 User-Agent,可能会被拒绝访问。
  2. IP 访问频率限制: 同一个 IP 在短时间内访问过于频繁,会被限制访问或封禁。
  3. Cookie 验证: 某些页面需要登录才能访问,或者需要携带特定的 Cookie 才能正常访问。
  4. 验证码: 遇到异常请求时,可能会弹出验证码。
  5. 数据加密: 某些数据可能经过加密处理,需要解密才能使用。
  6. 动态加载: 页面内容通过 JavaScript 动态加载,需要执行 JavaScript 才能获取完整数据。

二、应对策略

针对以上反爬机制,我们可以采取以下策略:

  1. 伪装 User-Agent:

这是最基本的操作。每次发起请求时,随机从一个 User-Agent 池中选择一个 User-Agent,模拟真实浏览器的行为。

import random

user_agents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0',
]

def get_random_user_agent():
    return random.choice(user_agents)

headers = {
    'User-Agent': get_random_user_agent()
}
  1. 使用代理 IP:

这是避免 IP 被封的最有效方法。使用大量的代理 IP,每次请求随机选择一个代理 IP,分散访问压力。

  • 获取代理 IP: 可以从一些免费或付费的代理 IP 网站获取。
  • 验证代理 IP: 获取到的代理 IP 可能不稳定,需要验证其可用性。可以使用 requests 库测试代理 IP 是否可用。
  • 维护代理 IP 池: 定期检查代理 IP 的可用性,移除失效的代理 IP。
import requests

proxies = [
    {'http': 'http://10.10.1.10:3128'},
    {'http': 'http://10.10.1.11:1080'},
]

def test_proxy(proxy):
    try:
        response = requests.get('https://www.douban.com', proxies=proxy, timeout=5)
        if response.status_code == 200:
            print(f'代理 {proxy} 可用')
            return True
        else:
            print(f'代理 {proxy} 不可用,状态码:{response.status_code}')
            return False
    except Exception as e:
        print(f'代理 {proxy} 连接失败:{e}')
        return False
  1. 控制访问频率:

不要过于频繁地访问豆瓣。可以设置一个合理的访问间隔,例如每隔几秒或十几秒访问一次。

import time

def crawl_data(url):
    # ...
    time.sleep(random.uniform(3, 5)) # 随机休眠 3-5 秒
    # ...
  1. 使用 Cookie 登录:

某些页面需要登录才能访问,可以先手动登录豆瓣,然后将 Cookie 保存下来,在爬虫中使用 Cookie 发起请求。

cookies = {
    'bid': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    # ... 其他 Cookie
}

response = requests.get(url, headers=headers, cookies=cookies)
  1. 处理验证码:

如果遇到验证码,可以尝试以下方法:

  • 手动输入验证码: 对于少量数据,可以手动输入验证码。
  • 使用验证码识别 API: 可以使用一些第三方验证码识别 API,自动识别验证码。
  1. 解析动态加载的内容:

如果页面内容通过 JavaScript 动态加载,可以使用以下方法:

  • Selenium: 使用 Selenium 模拟浏览器行为,执行 JavaScript,获取渲染后的页面内容。Selenium 的缺点是速度较慢。
  • Pyppeteer: Pyppeteer 是 Puppeteer 的 Python 版本,也可以用来执行 JavaScript。Pyppeteer 比 Selenium 更轻量级,速度更快。
  • 分析 Ajax 请求: 找到加载数据的 Ajax 请求,直接请求 Ajax 接口,获取数据。这种方法效率最高,但需要分析网页的 JavaScript 代码。
from selenium import webdriver

driver = webdriver.Chrome()
driver.get(url)
html = driver.page_source
driver.quit()
  1. 分布式爬取:

如果需要爬取的数据量非常大,可以考虑使用分布式爬取。将爬虫程序部署到多台机器上,同时进行爬取,可以大大提高爬取效率。需要注意,每台机器都需要使用不同的代理IP,避免被豆瓣识别为同一个用户。

三、实战案例:爬取豆瓣电影 Top250

下面是一个简单的爬取豆瓣电影 Top250 的示例代码:

import requests
from bs4 import BeautifulSoup
import random
import time

user_agents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0',
]

proxies = [
    # 填写你的代理IP
]


def get_random_user_agent():
    return random.choice(user_agents)


def get_random_proxy():
    if proxies:
        return random.choice(proxies)
    else:
        return None


def crawl_douban_top250(page):
    url = f'https://movie.douban.com/top250?start={page * 25}&filter='
    headers = {
        'User-Agent': get_random_user_agent()
    }
    proxy = get_random_proxy()
    if proxy:
        try:
            response = requests.get(url, headers=headers, proxies=proxy, timeout=10)
        except:
            print("代理出错,切换IP")
            return
    else:
        response = requests.get(url, headers=headers, timeout=10)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        movies = soup.find_all('div', class_='item')
        for movie in movies:
            title = movie.find('span', class_='title').text
            rating = movie.find('span', class_='rating_num').text
            print(f'电影名:{title},评分:{rating}')
    else:
        print(f'请求失败,状态码:{response.status_code}')

    time.sleep(random.uniform(3, 5))


if __name__ == '__main__':
    for page in range(10):
        crawl_douban_top250(page)

注意:

  • 请务必遵守豆瓣的 robots.txt 协议,不要爬取不允许爬取的页面。
  • 请合理控制访问频率,避免对豆瓣服务器造成过大的压力。
  • 请勿将爬取到的数据用于商业用途。
  • 示例代码中的 proxies 列表需要填写你自己的代理 IP。

四、总结

爬取豆瓣电影数据需要一定的技巧,但只要掌握了以上策略,就可以更高效、更安全地获取数据,同时避免被封 IP。记住,爬虫的本质是模拟用户行为,所以要尽量让你的爬虫看起来像一个真实用户。希望这些技巧能帮助你成功构建自己的电影推荐系统!

点评评价

captcha
健康