Kürzlich habe ich ein sehr interessantes Projekt auf GitHub entdeckt: GitHub Link.
Der Autor kombinierte geschickt GPT
und RPA
Technologie, um einen automatischen Assistenten für die Einreichung von Lebensläufen zu erstellen. Dies ist das vom ursprünglichen Autor geteilte Effektdemonstrationsvideo: Videolink zur B-Station.
Das ursprüngliche Projekt hatte jedoch folgende Probleme:
Nachdem ich erfolglos gekämpft hatte, entschied ich mich, Node.js zu verwenden, um das Projekt erneut zu implementieren. Es ist völlig kostenlos und kann mit einem Klick ausgeführt werden, ohne einen Agenten einzurichten: GitHub-Projektadresse.
In dieser kalten Recruiting-Saison kann Ihnen dieses Skript etwas Hilfe und Wärme spenden. Wenn Sie denken, dass dieses Projekt wertvoll ist, hoffe ich, dass Sie ihm helfen können, indem Sie ihm einen Stern geben.
Zunächst verwenden wir Selenium-Webdriver, um das Benutzerverhalten zu simulieren. Diese Bibliothek ist ein leistungsstarkes automatisiertes Testtool. Es ermöglicht die programmgesteuerte Steuerung von Browserinteraktionen und wird häufig für Aufgaben wie automatisierte Tests, Web Scraping und die Simulation von Benutzerinteraktionen verwendet.
DOM
Knoten der Anmeldeschaltfläche, simulieren Sie den Klick des Benutzers, um die Anmeldung auszulösen, und warten Sie, bis der Benutzer den QR-Code scannt.GPT
weiter und warten Sie auf die Antwort von GPT
GPT
geantwortet hat, klicken Sie auf die Schaltfläche „Jetzt kommunizieren“, um die Kommunikations-Chat-Oberfläche aufzurufenGPT
zurückgegebenen Informationen in das Chat-Feld ein und lösen Sie das Sendeereignis ausDiejenigen, die sich mit der GPT-Entwicklung beschäftigt haben, sollten wissen, dass für den Aufruf der GPT-Schnittstelle eine Zahlung erforderlich ist und der Aufladevorgang äußerst umständlich ist und die Verwendung ausländischer Bankkarten erfordert.
Um diesen Prozess zu vereinfachen, habe ich auf GitCode ein Projekt gefunden, das den kostenlosen API_KEY bereitstellt, den man einfach erhalten kann, indem man sich mit einem GitHub-Konto anmeldet.
Auf diese Weise können Sie den OpenAI-Client mit dem kostenlosen API_KEY
initialisieren.
// 初始化OpenAI客户端
const openai = new OpenAI ( {
// 代理地址,这样国内用户就可以访问了
baseURL : "https://api.chatanywhere.com.cn" ,
apiKey : "你的apiKey" ,
} ) ;
In diesem Schritt möchten wir den Browser öffnen und zur angegebenen URL navigieren. Der spezifische Vorgang besteht darin, die API von Selenium-Webdriver aufzurufen und den Code direkt einzugeben:
const { Builder , By , until } = require ( "selenium-webdriver" ) ;
const chrome = require ( "selenium-webdriver/chrome" ) ;
// 全局 WebDriver 实例
let driver ;
// 使用指定的选项打开浏览器
async function openBrowserWithOptions ( url , browser ) {
const options = new chrome . Options ( ) ;
options . addArguments ( "--detach" ) ;
if ( browser === "chrome" ) {
// 初始化一个谷歌浏览器客户端
driver = await new Builder ( )
. forBrowser ( "chrome" )
. setChromeOptions ( options )
. build ( ) ;
// 全屏打开浏览器
await driver . manage ( ) . window ( ) . maximize ( ) ;
} else {
throw new Error ( "不支持的浏览器类型" ) ;
}
await driver . get ( url ) ;
// 等待直到页面包含登录按钮dom
const loginDom = By . xpath ( "//*[@id='header']/div[1]/div[3]/div/a" ) ;
await driver . wait ( until . elementLocated ( loginDom ) , 10000 ) ;
}
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
await openBrowserWithOptions ( url , browserType ) ;
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
const url =
"https://www.zhipin.com/web/geek/job-recommend?ka=header-job-recommend" ;
const browserType = "chrome" ;
main ( url , browserType ) ;
In diesem Schritt müssen wir den DOM-Knoten der Anmeldeschaltfläche finden und dann das Klicken zum Anmelden simulieren.
// 省略上一步的代码
// 点击登录按钮,并等待登录成功
async function logIn ( ) {
// 点击登录
const loginButton = await driver . findElement (
By . xpath ( "//*[@id='header']/div[1]/div[3]/div/a" )
) ;
await loginButton . click ( ) ;
// 等待微信登录按钮出现
const xpathLocatorWechatLogin =
"//*[@id='wrap']/div/div[2]/div[2]/div[2]/div[1]/div[4]/a" ;
await driver . wait (
until . elementLocated ( By . xpath ( xpathLocatorWechatLogin ) ) ,
10000
) ;
const wechatButton = await driver . findElement (
By . xpath ( "//*[@id='wrap']/div/div[2]/div[2]/div[2]/div[1]/div[4]/a" )
) ;
// 选择微信扫码登录
await wechatButton . click ( ) ;
const xpathLocatorWechatLogo =
"//*[@id='wrap']/div/div[2]/div[2]/div[1]/div[2]/div[1]/img" ;
await driver . wait (
until . elementLocated ( By . xpath ( xpathLocatorWechatLogo ) ) ,
10000
) ;
// 等待用户扫码,登录成功
const xpathLocatorLoginSuccess = "//*[@id='header']/div[1]/div[3]/ul/li[2]/a" ;
await driver . wait (
until . elementLocated ( By . xpath ( xpathLocatorLoginSuccess ) ) ,
60000
) ;
}
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
// 点击登录按钮,并等待登录成功
+ await logIn ( ) ;
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
Nach erfolgreicher Anmeldung gelangen Sie zur Seite mit der Einstellungsinformationsliste. In diesem Schritt müssen wir die Einstellungsinformationen durchgehen und auf klicken, um die Stellenbeschreibungsinformationen für jede Einstellungsinformation zu finden, wie in der Abbildung dargestellt:
// 省略上一步的代码
// 根据索引获取职位描述
async function getJobDescriptionByIndex ( index ) {
try {
const jobSelector = `//*[@id='wrap']/div[2]/div[2]/div/div/div[1]/ul/li[ ${ index } ]` ;
const jobElement = await driver . findElement ( By . xpath ( jobSelector ) ) ;
// 点击招聘信息列表中的项
await jobElement . click ( ) ;
// 找到描述信息节点并获取文字
const descriptionSelector =
"//*[@id='wrap']/div[2]/div[2]/div/div/div[2]/div/div[2]/p" ;
await driver . wait (
until . elementLocated ( By . xpath ( descriptionSelector ) ) ,
10000
) ;
const jobDescriptionElement = await driver . findElement (
By . xpath ( descriptionSelector )
) ;
return jobDescriptionElement . getText ( ) ;
} catch ( error ) {
console . log ( `在索引 ${ index } 处找不到工作。` ) ;
return null ;
}
}
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
// 点击登录按钮,并等待登录成功
// 开始的索引
+ let jobIndex = 1 ;
+ while ( true ) {
+ // 获取对应下标的职位描述
+ const jobDescription = await getJobDescriptionByIndex ( jobIndex ) ;
+ console . log ( `职位描述信息/n: ${ jobDescription } ` ) ;
+ if ( jobDescription ) {
+ //
+ }
+ jobIndex += 1 ;
}
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
Kombinieren Sie dann die hochgeladenen Informationen zum Lebenslauf und zur Einstellung, leiten Sie sie an GPT
weiter und warten Sie auf die Antwort von GPT
:
// 省略上一步的代码
// 读取简历信息
const getResumeInfo = ( ) => {
fs . readFile ( "./简历基本信息.txt" , "utf8" , ( err , data ) => {
if ( err ) {
console . error ( "读取文件时出错:" , err ) ;
return ;
}
// 输出文件内容
return data ;
} ) ;
} ;
// 与GPT进行聊天的函数
async function chat ( jobDescription ) {
// 获取简历信息
const resumeInfo = getResumeInfo ( ) ;
const askMessage = `你好,这是我的简历: ${ resumeInfo } ,这是我所应聘公司的要求: ${ jobDescription } 。我希望您能帮我直接给HR写一个礼貌专业的求职新消息,要求能够用专业的语言将简历中的技能结合应聘工作的描述,来阐述自己的优势,尽最大可能打动招聘者。并且请您始终使用中文来进行消息的编写,开头是招聘负责人。这是一封完整的求职信,不要包含求职信内容以外的东西,例如“根据您上传的求职要求和个人简历,我来帮您起草一封求职邮件:”这一类的内容,以便于我直接自动化复制粘贴发送,字数控制在80字左右为宜` ;
try {
const completion = await openai . chat . completions . create ( {
messages : [
{
role : "system" ,
content : askMessage ,
} ,
] ,
model : "gpt-3.5-turbo" ,
} ) ;
// 获取gpt返回的信息
const formattedMessage = completion . choices [ 0 ] . message . content . replace (
/ n / g ,
" "
) ;
return formattedMessage ;
} catch ( error ) {
console . error ( `gpt返回时发生错误: ${ error } ` ) ;
const errorResponse = JSON . stringify ( { error : String ( error ) } ) ;
return errorResponse ;
}
}
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
// 点击登录按钮,并等待登录成功
// 开始的索引
while ( true ) {
// 获取对应下标的职位描述
if ( jobDescription ) {
// 发送描述到聊天并打印响应
+ const response = await chat ( jobDescription ) ;
+ console . log ( "gpt给的回复" , response ) ;
}
jobIndex += 1 ;
}
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
Nachdem die GPT-Antwort abgeschlossen ist, suchen Sie die Schaltfläche „Jetzt kommunizieren“ und simulieren Sie das Klicken darauf. Zu diesem Zeitpunkt gelangen Sie zur Kommunikations- und Chat-Schnittstelle, wie in der Abbildung gezeigt:
// 省略上一步的代码
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
// 点击登录按钮,并等待登录成功
// 开始的索引
while ( true ) {
// 获取对应下标的职位描述
if ( jobDescription ) {
// 发送描述到聊天并打印响应
// 点击沟通按钮
+ const contactButton = await driver . findElement (
+ By . xpath (
+ "//*[@id='wrap']/div[2]/div[2]/div/div/div[2]/div/div[1]/div[2]/a[2]"
+ )
+ ) ;
+ await contactButton . click ( ) ;
}
jobIndex += 1 ;
}
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
Rufen Sie an dieser Stelle die Chat-Oberfläche auf, geben Sie die GPT-Rückgabeinformationen in das Eingabefeld ein und lösen Sie das Sendeereignis aus.
// 省略上一步的代码
// 发送响应到聊天框
async function sendResponseToChatBox ( driver , response ) {
try {
// 请找到聊天输入框
const chatBox = await driver . findElement ( By . xpath ( "//*[@id='chat-input']" ) ) ;
// 清除输入框中可能存在的任何文本
await chatBox . clear ( ) ;
// 将响应粘贴到输入框
await chatBox . sendKeys ( response ) ;
await sleep ( 1000 ) ;
// 模拟按下回车键来发送消息
await chatBox . sendKeys ( Key . RETURN ) ;
await sleep ( 2000 ) ; // 模拟等待2秒
} catch ( error ) {
console . error ( `发送响应到聊天框时发生错误: ${ error } ` ) ;
}
}
// 主函数
async function main ( url , browserType ) {
try {
// 打开浏览器
// 点击登录按钮,并等待登录成功
// 开始的索引
while ( true ) {
// 获取对应下标的职位描述
if ( jobDescription ) {
// 发送描述到聊天并打印响应
// 点击沟通按钮
// 等待回复框出现
+ const chatBox = await driver . wait (
+ until . elementLocated ( By . xpath ( "//*[@id='chat-input']" ) ) ,
+ 10000
+ ) ;
+ // 调用函数发送响应
+ await sendResponseToChatBox ( driver , response ) ;
+ // 返回到上一个页面
+ await driver . navigate ( ) . back ( ) ;
+ await sleep ( 2000 ) ; // 模拟等待3秒
}
jobIndex += 1 ;
}
} catch ( error ) {
console . error ( `发生错误: ${ error } ` ) ;
}
}
Kehren Sie nach dem Absenden zur Einstellungslistenseite zurück und wiederholen Sie den Vorgang.
Dieses Projekt sendet einfach die Lebenslaufinformationen zusammen mit den Stelleninformationen an GPT und sendet dann die GPT-Antwort an den Personalvermittler. Tatsächlich ist dies nicht schwierig und soll neue Ideen anlocken.
Hier gibt es tatsächlich elegantere Möglichkeiten, z. B. die Weitergabe Ihres Lebenslaufs an GPT und die Extraktion effektiver Informationen durch GPT (dies hat der ursprüngliche Autor getan). Da das GPT-API-freie Projekt jedoch keine Assistenzdienste bereitstellt, ist hierfür eine Zahlung erforderlich. Freunde, die über Aufladekanäle verfügen, können es ausprobieren.
Darüber hinaus können Interessierte tiefer in die Materie eintauchen, zum Beispiel:
Abschließend wiederhole ich den Standpunkt des ursprünglichen Autors:
Ich hoffe, niemand wird mein Skript verwenden, um Lauch zu schneiden. Sie wurden bereits gezwungen, dieses Skript zu verwenden, um Lebensläufe einzureichen.