前言:为什么要学习爬虫

在当今数据驱动的时代,获取网络上的招聘信息对于求职者分析市场趋势、企业了解竞争对手薪资水平都非常有价值。本教程将带你从零开始,使用Playwright构建一个能够爬取Boss直聘岗位详情的爬虫程序。

即使你是编程新手,只要跟着本教程一步步操作,也能成功爬取到所需数据!

一、环境准备与安装

1.1 安装Python

首先确保你的电脑上安装了Python(3.7或更高版本)。可以从Python官网下载安装。

安装完成后,打开终端(Mac/Linux)或命令提示符(Windows),输入以下命令检查是否安装成功:

1
2
3
python --version
# 或
python3 --version

1.2 安装必要库

我们需要安装几个Python库来支持我们的爬虫:

1
pip install playwright yaml pyyaml

1.3 安装Playwright浏览器

Playwright需要安装浏览器内核才能工作:

1
playwright install chromium

这个过程可能会花费一些时间,因为它需要下载Chromium浏览器。

二、爬虫工作原理

2.1 导入必要的库

1
2
3
4
5
6
7
8
9
10
11
12
import asyncio
import json
import logging
import os
import re
import yaml
import time
from datetime import datetime
from typing import List, Dict, Any, Optional
from pathlib import Path

from playwright.async_api import async_playwright, Browser, Page, BrowserContext

这些库各自的作用:

  • asyncio: 用于异步编程,让爬虫可以高效处理多个任务
  • jsonyaml: 用于处理配置文件和保存数据
  • logging: 用于记录程序运行情况,方便调试
  • playwright: 核心库,用于控制浏览器

2.2 配置日志系统

1
2
3
4
5
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("boss_job_detail_crawler")

日志可以帮助我们了解程序运行状态,当出现问题时可以快速定位。

2.3 创建爬虫类

1
2
3
4
5
6
7
class BossJobDetailCrawler:
def __init__(self, headless: bool = False):
self.headless = headless # 是否无头模式(不显示浏览器界面)
self.browser = None # 浏览器对象
self.context = None # 浏览器上下文
self.page = None # 页面对象
self.playwright = None # Playwright实例

2.4 启动浏览器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async def start(self):
logger.info("启动浏览器...")
self.playwright = await async_playwright().start()

# 创建用户数据目录,用于保存登录状态
user_data_dir = os.path.expanduser('~/boss_crawler_data')
os.makedirs(user_data_dir, exist_ok=True)

# 启动浏览器
self.browser = await self.playwright.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
headless=self.headless,
channel="chrome", # 使用系统安装的Chrome
args=[
'--disable-blink-features=AutomationControlled', # 避免被检测为自动化工具
'--disable-web-security',
'--start-maximized'
],
viewport={'width': 1280, 'height': 800},
user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
)

这里有几个关键点:

  1. launch_persistent_context使用持久化上下文,可以保存cookies和登录状态
  2. headless=False表示显示浏览器界面,方便调试
  3. 设置用户代理(User-Agent)让请求看起来像来自真实浏览器

2.5 处理登录状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
async def ensure_logged_in(self):
logger.info("检查登录状态...")

# 访问Boss直聘首页
await self.page.goto("https://www.zhipin.com", wait_until="domcontentloaded")
await asyncio.sleep(3)

# 检查是否已登录的多个指标
login_indicators = [
'a[href*="/web/geek/chat"]', # 聊天入口
'.nav-figure img', # 用户头像
'a[ka="header-username"]', # 用户名链接
]

# 尝试找到登录指标
for indicator in login_indicators:
try:
element = await self.page.query_selector(indicator)
if element:
logger.info("检测到已登录状态")
return True
except:
continue

# 如果未登录,提示用户手动登录
logger.info("未检测到登录状态,请手动登录...")
logger.info("请在浏览器中完成登录,然后按Enter继续")
input("按Enter继续...")

# 等待用户登录
for _ in range(60): # 最多等待5分钟
await asyncio.sleep(5)
for indicator in login_indicators:
try:
element = await self.page.query_selector(indicator)
if element:
logger.info("登录成功!")
return True
except:
continue
logger.info("等待登录中...")

logger.error("登录超时")
return False

这个函数确保我们已经登录Boss直聘,因为未登录状态下无法查看岗位详情。

2.6 提取岗位详情

这是最核心的部分,我们需要从网页中提取所需信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
async def extract_job_details(self, job_url: str) -> Dict[str, Any]:
logger.info(f"开始提取岗位详情: {job_url}")

try:
# 导航到岗位详情页
await self.page.goto(job_url, wait_until="domcontentloaded")
await asyncio.sleep(3) # 等待页面加载

# 提取岗位信息
job_details = {
'url': job_url,
'title': await self._extract_text('.name h1'),
'salary': await self._extract_text('.salary'),
'city': await self._extract_text('.text-city'),
'experience': await self._extract_text('.text-experience'),
'education': await self._extract_text('.text-degree'),
'company': await self._extract_text('.company-info .name'),
'company_type': await self._extract_text('.company-info .type'),
'company_size': await self._extract_text('.company-info .size'),
'job_description': await self._extract_text('.job-sec-text'),
'extracted_at': datetime.now().isoformat()
}

# 提取标签信息
tags = await self._extract_tags()
if tags:
job_details['tags'] = tags

return job_details

except Exception as e:
logger.error(f"提取岗位详情失败: {e}")
# 保存错误截图便于调试
screenshot_path = f"error_screenshot_{int(time.time())}.png"
await self.page.screenshot(path=screenshot_path)
logger.info(f"已保存错误截图: {screenshot_path}")

return {
'url': job_url,
'error': str(e),
'extracted_at': datetime.now().isoformat()
}

2.7 辅助提取方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async def _extract_text(self, selector: str) -> str:
"""提取文本内容"""
try:
element = await self.page.query_selector(selector)
if element:
text = await element.text_content()
return text.strip() if text else ""
except:
pass
return ""

async def _extract_tags(self) -> List[str]:
"""提取标签信息"""
tags = []
try:
tag_elements = await self.page.query_selector_all('.job-tags span')
for tag_element in tag_elements:
tag_text = await tag_element.text_content()
if tag_text and tag_text.strip():
tags.append(tag_text.strip())
except:
pass
return tags

这两个辅助方法使用CSS选择器来定位和提取页面上的特定元素。

三、运行你的第一个爬虫

具体代码见 boss_crawl

3.1 创建配置文件

在代码同一目录下创建job_links.yaml文件:

1
2
3
4
5
6
7
8
job_links:
- https://www.zhipin.com/job_detail/第一个岗位的ID.html
- https://www.zhipin.com/job_detail/第二个岗位的ID.html
- https://www.zhipin.com/job_detail/第三个岗位的ID.html

output:
dir: ./job_details # 输出目录
format: json # 输出格式,可以是json或csv

将上面的URL替换为你想爬取的实际岗位链接。

3.2 运行爬虫

保存代码为boss_crawl.py,然后在终端中运行:

1
python boss_crawl.py

第一次运行时会弹出浏览器窗口,你需要手动登录Boss直聘。登录成功后,按终端中的Enter键,爬虫就会开始工作。

3.3 查看结果

爬虫完成后,会在job_details目录下生成一个包含时间戳的JSON或CSV文件,里面包含所有爬取到的岗位信息。

四、常见问题与解决方案

4.1 爬虫被检测到怎么办?

  • 调整user-agent,模拟真实浏览器
  • 增加随机延迟,模拟人类操作
  • 使用代理IP轮换请求

4.2 页面结构变化怎么办?

如果Boss直聘更新了页面结构,你需要更新代码中的CSS选择器。可以使用浏览器开发者工具检查元素,找到新的选择器。

4.3 如何提高爬取效率?

  • 使用异步并发处理多个页面
  • 合理设置请求延迟,既不太快触发反爬,也不太慢影响效率

五、注意事项

  1. 遵守Robots协议:检查Boss直聘的robots.txt文件,尊重网站的爬虫规则
  2. 限制爬取频率:不要过于频繁地请求,以免给网站服务器造成压力
  3. 合理使用数据:爬取的数据仅用于个人学习和研究,不要用于商业用途或侵犯他人隐私
  4. 注明数据来源:如果公开使用这些数据,请注明来自Boss直聘

结语

通过本教程,你学会了如何使用Playwright构建一个完整的爬虫程序,从环境搭建到实际运行,从页面导航到数据提取。这个技能不仅适用于Boss直聘,稍作修改也可以用于其他网站。

爬虫技术是一把双刃剑,希望你能合理使用它,在遵守法律和道德的前提下,获取对你有价值的数据。

如果你在实践过程中遇到任何问题,欢迎在评论区留言,我会尽力解答!


©2018 - Felicx 使用 Stellar 创建
总访问 113701 次 | 本页访问 326
共发表 98 篇Blog · 总计 142.3k 字