对于求职者、雇主或任何监测就业市场趋势的个人来说,搜索 Indeed 的可用职位列表可以提供有用的信息。在本教程中,我们将结合 Playwright(用于网络搜刮)和 lxml(用于 HTML 内容解析)来收集职位的详细信息,包括职位名称、招聘公司名称、地点、职位描述和职位发布链接,最后将信息保存到 CSV 文件中,以展示搜索结果。
用于浏览器自动化的 Playwright:
pip install playwright
lxml 用于解析 HTML:
pip install lxml
pandas 用于将数据保存到 CSV 文件:
pip install pandas
安装 Playwright 浏览器:
安装 Playwright 后,运行此命令安装必要的浏览器二进制文件:
playwright install
Playwright 允许您自动执行网页浏览器并与之交互。我们首先设置 Playwright 以启动 Chromium 浏览器、访问网页并提取其内容。在这里,我们还可以通过 playwright 传递代理。
为什么使用代理?
网站通常会设置速率限制或反搜索措施,以阻止来自同一 IP 地址的重复请求。代理允许您这样做:
import asyncio
from playwright.async_api import async_playwright
async def get_page_content(url):
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=False,
proxy = {
'server': '',
'username': '',
'password': ''
}
) # 标题浏览器
page = await browser.new_page()
await page.goto(url)
# 提取页面内容
content = await page.content()
await browser.close() # 完成后关闭浏览器
return content
在这段代码中,async_playwright 会启动一个浏览器,导航到指定的 URL 并获取页面内容。
接下来,我们将解析页面内容以提取有意义的数据。之所以使用 lxml,是因为它为使用 XPath 解析和查询 HTML 内容提供了强大的支持。
from lxml import html
def parse_job_listings(content):
# 解析 HTML 内容
parser = html.fromstring(content)
# 使用 XPath 提取每个招聘信息
job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
jobs_data = []
for element in job_posting[:-1]: # 如果是广告或无关内容,则跳过最后一个元素
title = ''.join(element.xpath('.//h2/a/span/@title'))
if title:
link = ''.join(element.xpath('.//h2/a/@href'))
location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))
# 将提取的数据添加到 jobs_data 列表中
jobs_data.append({
'Title': title,
'Link': f"https://www.indeed.com{link}",
'Location': location,
'Description': description,
'Company': company_name
})
return jobs_data
现在,我们已经设置了浏览器自动化和解析步骤,让我们将它们结合起来,从 Indeed 页面抓取职位列表。
说明:
import pandas as pd
async def scrape_indeed_jobs(url):
# 步骤 1:使用 Playwright 获取页面内容
content = await get_page_content(url)
# 第 2 步:解析 HTML 并提取任务详细信息
jobs_data = parse_job_listings(content)
return jobs_data
# 要搜索的 URL
url = 'https://www.indeed.com/q-usa-jobs.html'
# 抓取和保存数据
async def main():
# 从指定的 URL 抓取工作数据
jobs = await scrape_indeed_jobs(url)
# 第 3 步:使用 pandas 将数据保存为 CSV
df = pd.DataFrame(jobs)
df.to_csv('indeed_jobs.csv', index=False)
print("Data saved to indeed_jobs.csv")
# 运行主函数
asyncio.run(main())
Indeed 对其职位列表进行了分页处理,您可以轻松扩展 scraper 以处理多个页面。页面 URL 通过查询参数 start 进行调整,每新增一个页面,查询参数 start 将递增 10。
为了增强您的 scraper 从多个页面收集数据的功能,您可以实现一个名为 scrape_multiple_pages 的函数。该函数将通过逐步调整起始参数来修改基础 URL,从而访问后续页面。通过系统地逐步浏览每个页面,您可以扩大收集数据(如空缺职位)的范围和数量,从而确保获得更全面的数据集。
async def scrape_multiple_pages(base_url, pages=3):
all_jobs = []
for page_num in range(pages):
# 更新分页 URL
url = f"{base_url}&start={page_num * 10}"
print(f"Scraping page: {url}")
# 从每个页面抓取工作数据
jobs = await scrape_indeed_jobs(url)
all_jobs.extend(jobs)
# 将所有工作保存到 CSV
df = pd.DataFrame(all_jobs)
df.to_csv('indeed_jobs_all_pages.csv', index=False)
print("Data saved to indeed_jobs_all_pages.csv")
# 抓取多页招聘信息
asyncio.run(scrape_multiple_pages('https://www.indeed.com/jobs?q=usa', pages=3))
要在搜刮工作中瞄准特定的职位名称或关键词,您需要在 Indeed 使用的 URL 中配置查询搜索参数。这种自定义功能允许搜索器收集特定职位或行业的数据。例如,如果您要在 http://www.indeed.com 上搜索 Python 开发人员职位,您可以将查询参数调整为包含 "Python+developer "或相关关键词。
query = "python+developer"
base_url = f"https://www.indeed.com/jobs?q={query}"
asyncio.run(scrape_multiple_pages(base_url, pages=3))
根据您的数据收集需求修改该参数,您就可以将搜索重点放在特定职位上,从而提高数据收集过程的灵活性和效率。这种方法尤其适用于适应就业市场的动态需求。
import asyncio
from playwright.async_api import async_playwright
from lxml import html
import pandas as pd
# 步骤 1:使用 Playwright 获取页面内容
async def get_page_content(url):
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=False
proxy = {
'server': '',
'username': '',
'password': ''
}
) # 以标题模式运行浏览器
page = await browser.new_page()
await page.goto(url, wait_until='networkidle')
#提取页面内容
content = await page.content()
await browser.close() # 使用后关闭浏览器
return content
# 第 2 步:使用 lxml 解析 HTML 内容
def parse_job_listings(content):
# 使用 lxml 解析 HTML
parser = html.fromstring(content)
# 使用 XPath 选择单个职位发布
job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
# 提取工作数据
jobs_data = []
for element in job_posting[:-1]:
title = ''.join(element.xpath('.//h2/a/span/@title'))
if title:
link = ''.join(element.xpath('.//h2/a/@href'))
location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))
# 将提取的数据添加到 jobs_data 列表中
jobs_data.append({
'Title': title,
'Link': f"https://www.indeed.com{link}",
'Location': location,
'Description': description,
'Company': company_name
})
return jobs_data
# 第 3 步:为单个页面抓取 Indeed 招聘信息
async def scrape_indeed_jobs(url):
# 使用 Playwright 获取页面内容
content = await get_page_content(url)
# 解析 HTML 并提取工作数据
jobs_data = parse_job_listings(content)
return jobs_data
# 第 4 步:处理分页和搜索多个页面
async def scrape_multiple_pages(base_url, query, pages=3):
all_jobs = []
for page_num in range(pages):
# 更新 URL 以处理分页,并添加搜索查询
url = f"{base_url}?q={query}&start={page_num * 10}"
print(f"Scraping page: {url}")
# 抓取当前页面的工作
jobs = await scrape_indeed_jobs(url)
all_jobs.extend(jobs)
# 将所有工作保存到 CSV 文件
df = pd.DataFrame(all_jobs)
df.to_csv(f'indeed_jobs_{query}.csv', index=False)
print(f"Data saved to indeed_jobs_{query}.csv")
# 使用动态查询输入运行刮板的功能
async def run_scraper():
# 步骤 5:要求用户输入查询和要搜索的页面数
query = input("Enter the job title or keywords to search (e.g., python+developer): ")
pages = int(input("Enter the number of pages to scrape: "))
# 根据查询跨多个页面抓取作业
base_url = 'https://www.indeed.com/jobs'
await scrape_multiple_pages(base_url, query, pages)
# 运行刮刀
asyncio.run(run_scraper())
为确保刮奖过程顺利进行并降低出现拦截和验证码的风险,选择正确的代理服务器至关重要。互联网服务提供商(ISP)代理服务器是最理想的搜刮选择,它速度快、连接稳定、信任度高,因此很少被平台屏蔽。这类代理是静态的,因此要进行大规模搜索,就必须创建一个 ISP 代理池,并配置 IP 轮换以定期更换。另一种选择是住宅代理,它是动态的,与其他类型的代理服务器相比,具有最广泛的地理覆盖范围。
Мы получили вашу заявку!
Ответ будет отправлен на почту в ближайшее время.
С уважением proxy-seller.com!
评论: 0