影刀RPA 人力资源自动化:简历筛选与面试安排
影刀RPA 人力资源自动化简历筛选与面试安排什么情况用什么 → 怎么做 → 有什么坑作者林焱 | 飞行社出品什么情况用什么HR每天收到上百份简历手动筛选、打电话通知面试重复性工作占比超过60%。这套方案适合企业HR部门批量筛选简历猎头公司快速匹配候选人校园招聘大规模简历处理核心工具影刀RPA pdfplumber解析简历 python-docx生成面试通知 企微/邮件推送怎么做第一步批量接收和解析简历店群矩阵自动化突破运营极限importpdfplumberimportdocximportrefromdatetimeimportdatetimeimportosdefextract_resume_info(file_path):从简历中提取关键信息# 1. 提取文字iffile_path.endswith(.pdf):textwithpdfplumber.open(file_path)aspdf:forpageinpdf.pages:page_textpage.extract_text()ifpage_text:textpage_text\neliffile_path.endswith(.docx):docdocx.Document(file_path)text\n.join([para.textforparaindoc.paragraphs])# 2. 提取结构化信息info{}# 姓名通常在第一行first_linetext.split(\n)[0].strip()iflen(first_line)4:# 姓名一般不超过4个字info[姓名]first_line# 手机号phonere.search(r1[3-9]\d{9},text)ifphone:info[手机号]phone.group()# 邮箱emailre.search(r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,},text)ifemail:info[邮箱]email.group()# 工作年限work_yearsre.search(r(\d)\s*年.*?(?:工作|经验),text)ifwork_years:info[工作年限]int(work_years.group(1))# 最高学历educationre.search(r(?:本科|硕士|博士|大专|中专),text)ifeducation:info[学历]education.group()# 专业技能简单提取skills_keywords[Python,Java,SQL,Excel,RPA,影刀,UiPath]found_skills[kwforkwinskills_keywordsifkwintext]info[技能], .join(found_skills)# 期望薪资salaryre.search(r(?:期望|希望).*?(\d)[kK千],text)ifsalary:info[期望薪资]int(salary.group(1))info[原始文本]text[:500]# 只保留前500字info[文件名]os.path.basename(file_path)returninfo# 批量处理defbatch_process_resumes(folder_path):批量处理简历results[]forfilenameinos.listdir(folder_path):iffilename.endswith((.pdf,.docx)):file_pathos.path.join(folder_path,filename)print(f处理简历:{filename})try:infoextract_resume_info(file_path)results.append(info)exceptExceptionase:print(f处理失败{filename}:{e})returnresults第二步自动筛选简历评分模型classResumeScorer:简历自动评分器def__init__(self,job_requirements): job_requirements: 岗位要求字典 例如 { 最低学历: 本科, 最低工作年限: 3, 必须技能: [Python, SQL], 加分技能: [RPA, 影刀], 薪资上限: 30000 } self.requirementsjob_requirements# 学历权重用于评分self.EDUCATION_SCORE{博士:100,硕士:80,本科:60,大专:40,中专:20}defscore_resume(self,resume_info): 对简历评分返回 (总分, 是否推荐面试, 理由) score0reasons[]# 1. 学历评分30%权重educationresume_info.get(学历,)edu_scoreself.EDUCATION_SCORE.get(education,0)scoreedu_score*0.3ifeducation:reasons.append(f学历:{education}({edu_score}分))# 2. 工作年限评分20%权重work_yearsresume_info.get(工作年限,0)required_yearsself.requirements.get(最低工作年限,0)ifwork_yearsrequired_years:years_scoremin(work_years*10,100)# 最高100分scoreyears_score*0.2reasons.append(f工作年限:{work_years}年 ({years_score}分))else:reasons.append(f⚠️ 工作年限不足:{work_years}年要求{required_years}年)# 3. 技能匹配评分40%权重must_haveset(self.requirements.get(必须技能,[]))nice_haveset(self.requirements.get(加分技能,[]))candidate_skillsset(resume_info.get(技能,).split(, ))# 必须技能匹配度must_matchmust_havecandidate_skills must_scorelen(must_match)/len(must_have)*100ifmust_haveelse100scoremust_score*0.3reasons.append(f必须技能匹配:{len(must_match)}/{len(must_have)}({must_score:.0f}分))# 加分技能nice_matchnice_havecandidate_skills nice_scorelen(nice_match)/len(nice_have)*100ifnice_haveelse0scorenice_score*0.1reasons.append(f加分技能:{len(nice_match)}/{len(nice_have)}({nice_score:.0f}分))# 4. 薪资匹配10%权重expected_salaryresume_info.get(期望薪资,0)max_salaryself.requirements.get(薪资上限,999999)ifexpected_salarymax_salary:salary_score100scoresalary_score*0.1reasons.append(f薪资期望:{expected_salary}K 符合要求)else:salary_scoremax(0,100-(expected_salary-max_salary)/max_salary*100)scoresalary_score*0.1reasons.append(f⚠️ 薪资期望偏高:{expected_salary}K 上限{max_salary}K)# 判断是否推荐面试recommendscore60# 60分以上推荐面试return{总分:round(score,1),推荐面试:recommend,理由:; .join(reasons),匹配技能:list(must_match|nice_match)}# 使用示例requirements{最低学历:本科,最低工作年限:3,必须技能:[Python,SQL],加分技能:[RPA,影刀,UiPath],薪资上限:30000}scorerResumeScorer(requirements)# 对每份简历评分forresumeinresumes:resultscorer.score_resume(resume)resume[评分]result[总分]resume[推荐面试]result[推荐面试]resume[评分理由]result[理由]第三步自动发送面试通知importsmtplibfromemail.mime.textimportMIMETextfromemail.mime.multipartimportMIMEMultipartimportpandasaspddefsend_interview_invitation(resume_info,interview_time,interview_address):发送面试邀请邮件 短信# 1. 生成面试通知邮件email_contentf 尊敬的{resume_info[姓名]}先生/女士 感谢您应聘我司岗位经过初步筛选您的简历符合我们的要求现邀请您参加面试。 **面试信息** - 面试时间{interview_time}- 面试地点{interview_address}- 携带材料身份证、学历证书、简历打印版 如有任何问题请随时联系我们。 此致 敬礼 HR部{datetime.now().strftime(%Y年%m月%d日)}# 2. 发送邮件send_email(toresume_info[邮箱],subject面试邀请 - [公司名称],bodyemail_content)# 3. 发送短信通过企微/阿里云短信等sms_contentf【公司名称】尊敬的{resume_info[姓名]}您已通过简历筛选请于{interview_time}到{interview_address}参加面试。咨询电话010-xxxxxxxsend_sms(resume_info[手机号],sms_content)# 4. 记录通知状态log_notification(resume_info[手机号],面试邀请,interview_time)defsend_email(to,subject,body):发送邮件# 配置邮件服务器以QQ邮箱为例smtp_serversmtp.qq.comsmtp_port465sender_emailhrcompany.comsender_passwordyour_password# 授权码不是邮箱密码# 构造邮件msgMIMEMultipart()msg[From]sender_email msg[To]to msg[Subject]subject msg.attach(MIMEText(body,plain,utf-8))# 发送withsmtplib.SMTP_SSL(smtp_server,smtp_port)asserver:server.login(sender_email,sender_password)server.send_message(msg)print(f邮件已发送:{to})defsend_sms(phone,content):发送短信示例通过阿里云短信服务fromaliyunsdkcore.clientimportAcsClientfromaliyunsdkcore.request.v20170525importSendSmsRequest clientAcsClient(access_key_id,access_key_secret,cn-hangzhou)requestSendSmsRequest()request.set_PhoneNumbers(phone)request.set_SignName(公司名称)request.set_TemplateCode(SMS_123456789)request.set_TemplateParam({name: 候选人})responseclient.do_action_with_exception(request)print(f短信已发送:{phone})第四步面试安排与提醒defschedule_interviews(scored_resumes,interview_dates,interview_slots): 安排面试时间 scored_resumes: 按评分排序的简历列表 interview_dates: 可面试日期列表 interview_slots: 每天可面试时段如 [9:00-10:00, 10:00-11:00] schedule[]slot_index0# 只安排评分60的简历recommended[rforrinscored_resumesifr[推荐面试]]recommended.sort(keylambdax:x[评分],reverseTrue)# 高分优先forresumeinrecommended[:20]:# 每天最多安排20个面试# 分配面试时间date_idxslot_index//len(interview_slots)slot_idxslot_index%len(interview_slots)ifdate_idxlen(interview_dates):print(面试时段已用完)breakinterview_timef{interview_dates[date_idx]}{interview_slots[slot_idx]}schedule.append({姓名:resume[姓名],手机号:resume[手机号],邮箱:resume[邮箱],评分:resume[评分],面试时间:interview_time,状态:待面试})slot_index1returnscheduledefsend_interview_reminder(schedule,reminder_hours2): 面试前提醒 reminder_hours: 面试前多少小时提醒 fromdatetimeimportdatetime,timedelta nowdatetime.now()foriteminschedule:interview_timedatetime.strptime(item[面试时间],%Y-%m-%d %H:%M-%H:%M)# 计算距离面试还有多少小时hours_until(interview_time-now).total_seconds()/3600if0hours_untilreminder_hours:# 发送提醒reminder_contentf【面试提醒】尊敬的{item[姓名]}您今天{interview_time.strftime(%H:%M)}有面试请准时到达。地址xxx。咨询电话010-xxxxxxxsend_sms(item[手机号],reminder_content)print(f已发送提醒:{item[姓名]})第五步影刀RPA完整流程编排【定时触发】每天早上9点检查简历收件箱 ↓ 【读取邮件】获取附件简历PDF/Word ↓ 【Python节点】batch_process_resumes() → 批量解析简历 ↓ 【Python节点】scorer.score_resume() → 对每份简历评分 ↓ 【筛选】评分60的简历 ↓ 【Python节点】schedule_interviews() → 安排面试时间 ↓ 【循环】遍历面试安排 ↓ 【Python节点】send_interview_invitation() → 发送面试通知 ↓ 【写入Excel】更新面试安排表 ↓ 【企微通知】发送今日面试安排给HR团队 ↓ 【定时触发】面试前2小时 ↓ 【Python节点】send_interview_reminder() → 发送面试提醒有什么坑坑1简历格式千差万别解析准确率不稳定简历有各种格式创意型简历图表、特殊排版→ PDF解析混乱扫描版简历 → 需要OCR多语言简历中英文混排→ 提取困难解决方案# 1. 用多种工具组合解析defrobust_resume_parse(file_path):多种方法尝试解析# 方法1pdfplumber适合文本型PDFtry:textextract_text_pdfplumber(file_path)iflen(text)100:# 提取到足够文字returntextexcept:pass# 方法2OCR适合扫描版try:textextract_text_ocr(file_path)iflen(text)100:returntextexcept:pass# 方法3用大模型提取最准确但需要调用APItry:textextract_text_llm(file_path)returntextexcept:passreturn# 全部失败# 2. 对解析失败的简历转人工处理failed_resumes[]forresumeinresumes:ifnotresume.get(手机号)ornotresume.get(邮箱):failed_resumes.append(resume)print(f⚠️ 简历解析不完整转人工处理:{resume[文件名]})坑2评分模型不准确误筛优秀人才刚性评分标准可能误杀非典型优秀人才比如自学成才、学历不高但能力强的人。解决方案人工复审机制评分60-70分的简历转人工复审多维度评分除了硬性条件加入项目经验、开源贡献等软性指标A/B测试对比自动筛选 vs 人工筛选的录用率持续优化评分模型# 人工复审机制defmanual_review_if_needed(resume,score):评分在阈值附近的转人工复审if50score70:# 临界区域add_to_manual_review_queue(resume)return待人工复审[video(video-kuTpffpY-1783725286195)(type-csdn)(url-https://live.csdn.net/v/embed/524992)(image-https://v-blog.csdnimg.cn/asset/b59aed2f01d4fe8583467562aaf4dcfd/cover/Cover0.jpg)(title-temu店群自动化报活动案例)]elifscore70:return推荐面试else:return不推荐坑3邮件/短信被当成垃圾邮件/骚扰短信批量发送面试通知容易被邮件服务商判定为垃圾邮件或被用户投诉为骚扰短信。解决方案使用企业邮箱不要用个人邮箱申请短信模板向短信服务商申请正规模板提供退订选项邮件末尾加如果不想接收请回复退订# 邮件末尾加退订说明email_content --- 如果您不希望收到我们的邮件请回复退订我们将把您从邮件列表中移除。 坑4面试安排冲突时间重叠、面试官冲突如果多个HR同时安排面试可能出现时间冲突。解决方案用共享日历腾讯会议/飞书日历或数据库锁机制# 用数据库锁防止冲突importsqlite3defreserve_interview_slot(datetime_slot):预约面试时段加锁connsqlite3.connect(interview.db)cursorconn.cursor()try:# 加锁防止并发冲突cursor.execute(BEGIN IMMEDIATE TRANSACTION)# 检查时段是否已被预约cursor.execute( SELECT COUNT(*) FROM interview_schedule WHERE interview_time ? ,(datetime_slot,))countcursor.fetchone()[0]ifcount0:conn.rollback()returnFalse# 时段已被预约# 预约时段cursor.execute( INSERT INTO interview_schedule (interview_time, status) VALUES (?, reserved) ,(datetime_slot,))conn.commit()returnTrue# 预约成功exceptExceptionase:conn.rollback()returnFalsefinally:conn.close()总结功能节省时间附加价值简历解析每份省5分钟结构化数据便于分析自动评分每份省10分钟客观公正减少人为偏见面试安排每个省15分钟避免时间冲突自动通知每个省5分钟及时沟通提升候选人体验实际落地建议先小范围测试用50份简历测试评分模型对比人工筛选结果持续优化评分规则根据实际录用率调整各维度权重保留人工复审环节自动筛选 人工复审双重保障注意隐私保护简历数据加密存储只用于招聘用途HR自动化能为招聘团队节省70%以上的筛选时间让HR专注于更高价值的工作如人才评估、文化匹配等。