为什么写了这个教程?
第一天被封IP,第二天遇到动态加载,第三天发现数据全是加密的。三天没睡好,最后用Selenium模拟浏览器才勉强交差,还被客户嫌弃拖了工期。
*开篇配图:一张典型爬虫工作流示意图,从URL请求→页面渲染→数据提取→存储*
案例1:抓静态HTML页面——别被requests的“简单”骗了
/06/agnes_46c638e41cdf_0-1.png” alt=”案例1:抓静态HTML页面——别被requests的“简单”骗了 – Python爬虫从零到实战:3个案例搞定反爬与数据提取”
style=”max-width:100%;height:auto;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.08);”
loading=”lazy” width=”800″ height=”500″>
先看最基础的情况:页面内容直接写在HTML里。比如你要爬某个技术博客的文章标题和发布时间,打开开发者工具看到这样的结构:
“html
Python内存管理详解
2024-03-15
`
为什么用requests+BeautifulSoup? 因为轻量、快、不用调浏览器。但注意:一定要加请求头,否则大概率被拦。一开始我就忘了加,结果一直返回空,我以为网站挂了,后来才发现是UA没伪装。
`python
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': 'https://example.com/', # 很多反爬会检查这个
}
response = requests.get('https://ex
ample.com/blog', headers=headers, timeout=10)
优先用响应头编码,apparent_encoding是备选,避免短文本推测不准
response.encoding = response.apparent_encoding if response.apparent_encoding else 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
用CSS选择器提取,比find_all更直观
posts = []
for item in soup.select('div.post-item'):
title = item.select_one('h2.title').text.strip()
date = item.select_one('span.date').text.strip()
posts.append({'title': title, 'date': date})
print(f'成功抓取 {len(posts)} 篇文章')
`
第一个坑:你以为这样就完了?实际运行后可能返回空列表。原因很可能是页面使用了JavaScript动态加载数据。我靠,当时我就怀疑自己代码写错了,排查了半天,结果发现是页面用了Vue渲染数据。先检查页面源码(右键→查看网页源代码)——如果标题和日期不在源码里,说明你需要下面这个方法。
案例2:抓动态加载页面——Selenium的正确打开方式
另一个坑:现在大量网站用Vue/React前端框架,内容通过AJAX异步加载。比如你要爬某个招聘网站的职位列表,明明开发者工具能看到数据,requests却拿不到。真的服了。
*核心配图:对比静态页面源码和动态渲染后的DOM结构差异*
为什么用Selenium? 因为它会完整渲染JavaScript,模拟真实浏览器行为。但注意:不要直接无脑用,先配置好headless模式和无头浏览器优化,不然每次弹个浏览器窗口,看着就烦:
`python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头模式,不弹浏览器窗口
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化特征
额外隐藏自动化标志,Chrome 120+推荐用这个替代上面的参数
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
driver = webdriver.Chrome(options=chrome_options)
driver.get('https://example.com/jobs')
关键:用显式等待,而不是time.sleep()
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.job-item')))
滚动页面以触发懒加载
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
等待懒加载内容出现,用显式等待替代固定sleep
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.job-item.lazy-loaded')))
提取数据
for item in driver.find_elements(By.CSS_SELECTOR, 'div.job-item'):
title = item.find_element(By.CSS_SELECTOR, 'h3.job-title').text
salary = item.find_element(By.CSS_SELECTOR, 'span.salary').text
print(f'{title}: {salary}')
driver.quit()
`
个人吐槽:Selenium这个设计真的反人类——每次启动都要加载整个Chromium,慢到怀疑人生。我一开始用的时候,等了十几秒才出页面,差点以为电脑坏了。但没办法,对付动态页面它就是最靠谱的。后来我发现了undetected-chromedriver这个库,能更好地规避反爬检测,推荐试试。安装很简单:pip install undetected-chromedriver,然后替换webdriver.Chrome为undetected_chromedriver.Chrome。
性能数据:带图片加载的页面,从最初3.2秒降到优化后的0.8秒(禁用图片+CSS)。方法是在options里加:
`python`
prefs = {"profile.managed_default_content_settings.images": 2,
"profile.default_content_setting_values.notifications": 2}
chrome_options.add_experimental_option("prefs", prefs)
案例3:抓反爬严格的站点——接口模拟与随机延迟
第三个坑:有些网站会检测IP请求频率、检查User-Agent连续性、甚至用WebDriver检测。比如某鱼、某瓣这类平台,反爬做得跟铁桶一样。
正确的策略:
来看具体实现:
`python
import requests
import time
import random
from fake_useragent import UserAgent # 库名是fake-useragent,安装用pip install fake-useragent
ua = UserAgent(browsers=['chrome', 'firefox']) # 限制浏览器类型,避免UA列表过时问题
def fetch_page(url, cookies, max_retries=3):
headers = {
'User-Agent': ua.random, # 每次请求不同UA
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://example.com/', # 来源页不能错
'X-Requested-With': 'XMLHttpRequest',
}
for attempt in range(max_retries):
time.sleep(random.uniform(1.5, 3.0)) # 关键:随机延迟
response = requests.get(url, headers=headers, cookies=cookies)
if response.status_code == 200:
return response.json()
elif response.status_code == 429: # 限流,需要更长的等待
wait_time = 5 * (attempt + 1) # 递增等待时间
print(f'被打回,等待{wait_time}秒重试...')
time.sleep(wait_time)
else:
response.raise_for_status()
raise Exception(f'重试{max_retries}次后仍失败')
使用示例
安全提示:从浏览器开发者工具→Application→Cookies复制session_id,不要硬编码敏感信息
推荐使用EditThisCookie等扩展导出,或手动复制后立即使用
cookies = {'session_id': 'your_session_here'} # 从浏览器复制,用完即删
data = fetch_page('https://api.example.com/items?page=1', cookies)
`
另一个坑:很多新人喜欢一次抓几十页,然后被封。聪明做法是加个重试机制,配合指数退避。用urllib3的Retry类更省事:
`python
from urllib3.util import Retry # 注意Retry首字母大写
from requests.adapters import HTTPAdapter
session = requests.Session()
backoff_factor=2,重试间隔为2秒、4秒、8秒...应对429错误更稳妥
retries = Retry(total=3, backoff_factor=2, status_forcelist=[429, 500, 502, 503])
session.mount('https://', HTTPAdapter(max_retries=retries))
`
进阶技巧:数据存储与异常处理
爬下来的数据怎么存?我一般用CSV,简单又好读。但有个坑:中文编码问题。如果你直接pd.to_csv(‘data.csv’),打开Excel全是乱码。正确姿势:
`python
import csv
用csv模块写,指定utf-8-sig编码,Excel能直接打开
with open('data.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL) # 只对含特殊字符的字段加引号,避免不必要的引号
writer.writerow(['标题', '日期', '价格'])
for item in data:
writer.writerow([item['title'], item['date'], item['price']])
`
异常处理:爬虫最怕跑一半挂了。我习惯用try-except包住关键步骤,配合日志记录:
`python
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def safe_request(url, retries=3):
for i in range(retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
logging.warning(f'第{i+1}次请求失败: {e}')
time.sleep(2 ** i) # 指数退避
logging.error(f'请求{url}失败,已重试{retries}次')
return None
`
总结:我的爬虫避坑清单
最后说一句:爬虫技术本身是中性的,但别用来干坏事。尊重网站的robots.txt,别爬登录后的敏感数据,更别把人家服务器搞崩了。技术是工具,人品是底线。
*结尾配图:一张爬虫工作流总结图,展示从目标分析到数据存储的完整链路*
附:常用工具速查表
| 场景 | 推荐工具 | 安装命令 |
|------|---------|---------|
| 静态页面 | requests + BeautifulSoup | pip install requests beautifulsoup4 |pip install selenium undetected-chromedriver
| 动态页面 | Selenium + undetected-chromedriver | |pip install requests fake-useragent
| 接口模拟 | requests + fake-useragent | |pip install pandas` |
| 数据存储 | pandas / csv |