
Python后端爬虫专题28不是“我学过爬虫”——毕业验收、简历项目与面试答辩上一篇练习完整答案完整部署证据应包括docker compose ps中 api、worker、postgres、redis、minio、targetlab 均 healthymigrate exited(0)首次公开旅程状态从 queued/running 到 completedreport 的 created3、jobs total3同租户第二次 created0、not_modified3、jobs仍3。若你的数据库已有历史数据数字以重置前状态为基准不要为了得到漂亮输出删除卷。只重启 api/worker 后查询仍返回三条随后增量任务仍能读取旧 ETag 并得到 304证明事实与 validators 位于 PostgreSQL volume而非进程内变量。进一步重建容器仍保留数据也可作为证据volume 仍不等于异机备份。MinIO bucket 中应有按快照标识命名的.html与.json元数据含 URL、抓取时间、白名单响应头和正文 SHA-256而无 Cookie/AuthorizationWorkercrawl_started与crawl_finished可用相同 task_id 关联结束事件含 report 与 metrics。若日志出现密码或会话值验收必须失败并先轮换凭据。先提交一张能力证据表能发送请求HttpFetcher 测 429、503、304、重定向、DNS 与大小上限能解析Fixture 覆盖列表、详情和缺字段能保证数据Pydantic、指纹、唯一约束、快照、事务能扩展框架Scrapy 与 Playwright 都复用 JobItem能做后端FastAPI 202、Celery、Redis、任务状态、租户隔离能部署Alembic、PostgreSQL、MinIO、Compose能运维结构化日志、指标、恢复演练。证据不是代码文件数量而是可以重复运行的命令与可观察结果。最终全量检查cd project.\.venv\Scripts\python.exe-m pytest-q.\.venv\Scripts\python.exe-m compileall-q src targetlab scripts tests migrations docker compose config--quiet课程根目录再执行逐篇 QA 与 28 个检查点cd...\project\.venv\Scripts\python.exe tools\sync_complete_modules.py--check.\project\.venv\Scripts\python.exe tools\course_qa.py.\project\.venv\Scripts\python.exe tools\verify_checkpoints.py任何一项失败都不能用“主要功能正常”带过。先按错误定位到文章、模块或运行环境修复后重跑完整命令。用用户旅程做毕业演示演示顺序控制在十分钟介绍授权边界与 TargetLab通过 API 创建任务解释 202观察 Worker 日志中的 task_id查询 completed 报告和职位第二次运行展示 304/幂等打开 MinIO 说明原始证据调用 analytics导出 JSONL 给后续 AI/RAG最后展示一个 SSRF 测试与坏详情 partial 测试。这比从上到下念源码更像后端工程师。面试官追问时再进入pipeline.py或worker.py解释接口与故障边界。简历怎样写得可验证可以写独立实现合规招聘信息采集后端 JobRadar基于 FastAPI、Celery/Redis、PostgreSQL 与 MinIO 建立异步任务、原始快照和租户隔离实现 ETag 增量采集、内容指纹幂等、robots/SSRF/重定向/响应大小防护并用 pytest、ASGITransport 与 Docker Compose 验证首次采集、304 重跑、内容更新和 Worker 恢复链路。不要写“精通分布式爬虫”“支持亿级数据”除非你做过对应规模测试。可以补充真实指标测试数量、旅程耗时、默认并发、样本规模但每个数字必须来自当前运行证据并说明课程规模不等于生产容量。高频面试题逐层回答为什么不用requestsHTTPX 同时提供 sync/async、流式响应和 ASGITransport适合本项目选择工具不是说 requests 不好。为什么要保存HTML结构化行无法解释选择器失效、登录页替换或源站真实变更快照支持离线重放与审计保存时排除敏感头并设置保留策略。如何去重单次 URL set、调度器请求指纹、数据库租户source_url唯一约束、业务内容 SHA-256 各处理不同阶段重复运行仍会更新 last_seen 与 validators。如何增量Repository 取 ETag/Last-ModifiedHttpFetcher 发条件请求304 不解析空正文、不写空快照200 再指纹比较定期无条件巡检应对错误缓存头。如何防SSRF精确 allowlist、禁止凭据 URL、解析后 IP 分类、每跳重定向复检、响应大小/超时限制再叠加容器与云网络出站 ACL。Celery能保证只执行一次吗不能。late ack 改善 Worker 丢失恢复但提交后未 ack 会重投靠幂等写入收敛。API 落库与入队的原子性进一步可用 transactional outbox。Scrapy与Playwright怎么选静态/公开 JSON 优先 HTTP复杂链接调度用 Scrapy只有获准且确需执行脚本时用 Playwright三条路线共享业务模型与持久化规则。为什么任务表不只用Celery backend业务状态需要稳定 ID、租户权限、长期报告和独立生命周期队列结果是基础设施状态且可能过期。面试现场的架构追问若扩展到多来源不先复制 Spider而是为每个来源实现“发现详情/解析详情或 JSON”的 adapter共享政策、Fetcher、JobItem、Repository 和任务报告按 host 做全局限速。若数据量变大分析聚合下推 PostgreSQL快照生命周期化任务分片并增加 backpressure。若需要 AI使用scripts.export_jobs输出带 schema_version 与 source_url 的 JSONL进行清洗、切分、向量化与 RAG检索答案必须回链职位来源与发布时间。模型输出不是事实表不能回写覆盖 JobRecord。若被问反爬不谈验证码破解、指纹伪装和代理池。说明通过授权、正式 API、robots、频率预算、条件请求和停止机制减少影响。工程竞争力包括知道什么时候不采集。最终交付结构articles是连续讲义project是可独立安装运行的完整项目assets是逐篇 PNG 与 CSDN 封面checkpoints/manifest.json将每篇绑定真实 pytest 行为reports保存课程、检查点、项目与图片验收证据。读者可以只发布 Markdown也可以拉起全部容器复现。本篇完整AI/RAG交接模块结课用 exporter 收束它把数据库事实转换回 JobItem只导出指定租户以临时文件原子替换并携带 schema_version。调用者是python -m scripts.export_jobs输出是可逐行读取的 UTF-8 JSONL失败时旧完整文件不会被半截内容覆盖。JobRadar 到数据分析或 AI/RAG 系统的稳定 JSONL 交接合同。importjsonfrompathlibimportPathfromtypingimportIterablefromsqlalchemy.ormimportSession,sessionmakerfrom.modelsimportJobItemfrom.repositoryimportJobRecord,JobRepositorydefexport_jobs_jsonl(jobs:Iterable[JobItem],destination:Path)-int:原子替换一份 UTF-8 JSONL 导出避免重复运行不断追加旧数据。destinationdestination.resolve()destination.parent.mkdir(parentsTrue,exist_okTrue)temporarydestination.with_suffix(destination.suffix.tmp)count0withtemporary.open(w,encodingutf-8,newline\n)asoutput:forjobinjobs:row{schema_version:jobradar.job.v1,**job.model_dump(modejson)}output.write(json.dumps(row,ensure_asciiFalse,separators(,,:)))output.write(\n)count1temporary.replace(destination)returncountdefexport_tenant_jobs(session_factory:sessionmaker[Session],tenant_id:str,destination:Path)-int:从数据库读取一个租户的职位再复用稳定的 JSONL 写出合同。withsession_factory()assession:rowsJobRepository(session).list_jobs(tenant_id,limit100_000)jobs[_record_to_item(row)forrowinrows]returnexport_jobs_jsonl(jobs,destination)def_record_to_item(row:JobRecord)-JobItem:只导出业务事实不把租户、内部主键或抓取时间混入下游合同。returnJobItem(external_idrow.external_id,source_urlrow.source_url,titlerow.title,companyrow.company,cityrow.city,descriptionrow.description,skillslist(row.skills),salary_minrow.salary_min,salary_maxrow.salary_max,salary_monthsrow.salary_months,published_atrow.published_at,)毕业验收标准你应能在不看答案的情况下解释并演示合法边界HTTP 状态/缓存DOM与JSON解析数据校验快照重放幂等并发预算Scrapy与Playwright取舍Celery故障窗口FastAPI租户接口统计口径SSRF防御分层测试Compose恢复JSONL接入RAG。缺哪一项就回到对应文章和独立检查点补齐而不是只背最终代码。