在这篇文章里,我们将使用Crawlee和Streamlit构建一个网络应用程序,用于从LinkedIn上抓取数据。
我们将使用Python的Crawlee库创建一个LinkedIn工作抓取器,该抓取器可以从Web应用程序中动态接收的用户输入中提取公司名称、职位标题、发布时间和工作发布链接。
注意
我们的一位社区成员写了一篇博客投稿到Crawlee Blog。如果您也有类似的文章想要投稿,可以通过我们的discord频道与我们联系。
完成本教程时,您将能够使用一个功能完整的网络应用从LinkedIn上收集工作招聘信息。
咱们开始啦。
此处省略
先决条件让我们开始通过运行以下命令来创建一个新的Crawlee for Python项目:
# 如下所示
运行pipx来运行crawlee并创建一个名为linkedin-scraper的项目
全屏模式 退出全屏
当 Crawlee 在终端中要求你选择时,选择 PlaywrightCrawler
。
安装完成后,Crawlee for Python 会自动生成样板代码。你可以使用 cd
命令切换到项目文件夹,然后运行此命令来安装所需的依赖包。
poetry install # 这里我们使用poetry来安装依赖包。
点这里进入全屏,点击退出全屏
我们要开始处理Crawlee提供的文件,以便能够构建我们的抓取器。
用Python和Crawlee构建LinkedIn工作爬虫注意
如果你喜欢这篇博客,能在 GitHub 上给 Crawlee for Python 点个赞就太好了。给我们的项目点个赞吧 ⭐️
在这节,我们将使用Python版的Crawlee包来构建爬虫程序。想了解更多关于Crawlee的信息,请参阅他们的文档。
1. 查看领英的工作岗位搜索页面
在您的网络浏览器里打开LinkedIn网站,然后退出网站(如果您已登录账户)。您应该看到类似这样的界面。
进入工作部分,搜索你想要的工作和地点,然后复制该工作页面的网址。
你应该有这样类似的东西:
https://www.linkedin.com/jobs/search?keywords=后端开发者&location=Canada&geoId=101174742&trk=public_jobs_jobs-search-bar_search-submit&position=1&pageNum=0
我们要特别注意的是,在'? '后面的搜索参数,尤其是关键词和位置参数,对我们来说最关键。
用户提供的岗位名称将作为关键词参数输入,而用户提供的地点将作为位置参数输入。最后,我们将移除geoId
参数,保持其他参数原样。
我们将对main.py
文件做一些改动。将下面的代码复制粘贴到你的main.py
文件中。
from crawlee.playwright_crawler import PlaywrightCrawler
from .routes import router
import urllib.parse
async def main(title: str, location: str, data_name: str) -> None:
base_url = "https://www.linkedin.com/jobs/search"
# 对 URL 参数进行编码
params = {
"keywords": title,
"location": location,
"trk": "public_jobs_jobs-search-bar_search-submit",
"position": "1",
"pageNum": "0"
}
encoded_params = urlencode(params)
# 将这些参数编码成查询字符串
query_string = '?' + encoded_params
# 将基础 URL 和已编码的查询字符串拼接起来
encoded_url = urljoin(base_url, "") + query_string
# 初始化爬虫实例
crawler = PlaywrightCrawler(
request_handler=router,
)
# 使用包含初始 URL 的列表运行爬虫
await crawler.run([encoded_url])
# 等待爬虫将数据导出到 CSV 文件中
output_file = f"{data_name}.csv"
await crawler.export_data(output_file)
点击这里进入全屏模式,点击这里退出全屏模式
现在我们已经对URL进行了编码,接下来我们需要调整生成的路由来处理LinkedIn上的工作帖子。
2. 为您的爬虫设置路由
我们将为你的应用使用两个处理单元:
- 默认处理方式
default_handler
处理的是初始URL
- 找工作
job_listing
处理程序提取每项工作的详细信息。
职位爬虫将爬取职位发布页面上的信息,并提取所有职位发布的链接。
当你查看职位发布时,你会发现这些链接就是职位发布,位于一个名为 jobs-search__results-list
的有序列表中。我们将利用 Playwright 定位器来提取这些链接,并将它们加入到 job_listing
路由中处理。
router = Router[PlaywrightCrawlingContext]()
@router.default_handler
async def default_handler(context: PlaywrightCrawlingContext) -> None:
"""默认请求处理器."""
#select all the links for the job posting on the page
hrefs = await context.page.locator('ul.jobs-search__results-list a').evaluate_all("links => links.map(link => link.href)")
#add all the links to the job listing's route
await context.add_requests(
[Request.from_url(rec, label='job_listing') for rec in hrefs]
)
全屏,退出全屏
现在我们已经拿到了工作列表,下一步是获取它们的详细信息吧。
我们将提取每个工作的标题、公司的名称、时间以及工作帖子链接。打开您的开发工具面板,使用 CSS 选择器来提取每个元素。
在抓取后处理每个列表后,我们将清理文本中的特殊字符,并使用context.push_data
函数将数据存储到本地。
@router.handler('job_listing')
async def listing_handler(context: PlaywrightCrawlingContext) -> None:
"""处理职位列表的函数。"""
await context.page.wait_for_load_state('load')
job_title = await context.page.locator('div.top-card-layout__entity-info h1.top-card-layout__title').text_content()
company_name = await context.page.locator('span.topcard__flavor a').text_content()
time_of_posting = await context.page.locator('div.topcard__flavor-row span.posted-time-ago__text').text_content()
await context.push_data(
{
# 我们使用正则表达式来移除提取文本中的空格和换行符
'title': re.sub(r'[\s\n]+', '', job_title),
'公司名称': re.sub(r'[\s\n]+', '', company_name),
'发布时间': re.sub(r'[\s\n]+', '', time_of_posting),
'url': context.request.loaded_url,
}
)
进入全屏模式。退出全屏模式。
3. 创建你的应用。对于此项目,我们将使用Streamlit来创建网络应用。在我们继续之前,我们将在项目目录中创建一个名为app.py
的新文件。此外,请确保您已经在全局Python环境中安装了Streamlit,然后再继续此部分。
import streamlit as st
import subprocess
# Streamlit 表单输入
st.title("LinkedIn 职位爬虫")
with st.form("scraper_form"):
title = st.text_input("职位标题", value="backend developer")
location = st.text_input("工作地点", value="newyork")
data_name = st.text_input("文件名", value="backend_jobs")
submit_button = st.form_submit_button("开始爬取")
if submit_button:
# 使用表单输入运行爬虫脚本
command = f"""poetry run python -m linkedin-scraper --title "{title}" --location "{location}" --data_name "{data_name}" """
with st.spinner("正在爬取..."):
# 执行命令并显示结果
result = subprocess.run(command, shell=True, capture_output=True, text=True)
st.write("脚本结果:")
st.text(result.stdout)
if result.returncode == 0:
st.success(f"数据已成功保存为 {data_name}.csv")
else:
st.error(f"错误信息: {result.stderr}")
切换到全屏模式 退出全屏
Streamlit网络应用接受用户的输入,并使用Python的subprocess模块来运行Crawlee抓取脚本。
4. 测试你的 app在测试应用程序之前,我们先需要对__main__
文件进行一些调整,以便它能接受命令行参数。
import asyncio
import argparse
from .main import main
def get_args():
# ArgumentParser对象用于从LinkedIn爬取职位列表
parser = argparse.ArgumentParser(description="从LinkedIn爬取职位列表")
# 定义以下参数
parser.add_argument("--title", type=str, required=True, help="职位名称(必填)")
parser.add_argument("--location", type=str, required=True, help="职位地点(必填)")
parser.add_argument("--data_name", type=str, required=True, help="输出CSV文件的名称(必填)")
# 解析参数
return parser.parse_args()
if __name__ == '__main__':
args = get_args()
# 运行主函数并传递解析后的参数
asyncio.run(main(args.title, args.location, args.data_name))
进入全屏 退出全屏
我们将在终端中运行以下代码来启动Streamlit应用程序:
在命令行中运行 `streamlit run app.py` 这个命令
全屏模式, 退出全屏
比如你这个应用在浏览器里应该看起来是这样的。
你会看到一个界面,显示爬虫运行已完成。
要查看抓取的数据,请进入您的项目文件夹,然后打开CSV文件就可以了。
你的 CSV 文件输出应该像这样。
结尾.在这篇指南中,我们学习了如何使用Crawlee抓取LinkedIn上的职位信息。希望你使用Crawlee构建抓取应用时能玩得开心。
你可以在这个链接中找到完整的爬虫,在 GitHub 仓库。
关注Crawlee,查看更多这样的内容。
Crawlee 关注一下(了解更多关于Crawlee的信息)Crawlee 是一个用于网页抓取和浏览器自动化的库,可以帮助你快速地构建可靠的爬虫。
谢谢。