今年工作这么难找,身为一名开发者该怎么办?

今年工作难找,这个已经是不争的事实了,至于说为什么工作难找,我想大家大概都知道,无非就是大环境不好,业务锐减 + AI 人工智能的普及,企业管理者不愿意再多花费成本,而是想尽最大力度的去压榨完当前人的剩余价值。

目录

一、国际关系与外部环境对IT行业的传导效应

二、行业收缩引发的"技术栈通胀"现象

三、AI普及引发的技能迁移压力

四、市场供需失衡下的"全栈化生存"

突围建议(Java开发者视角)


今年工作难找的原因,我觉得可以从如下的四个方面去探讨一下:

一、国际关系与外部环境对IT行业的传导效应

  1. 全球供应链重构:中美技术脱钩背景下,跨国企业(尤其芯片、云计算等领域)在华研发中心招聘规模缩减,部分外企将技术团队转移至东南亚,直接影响中高端岗位供给。

  2. 资本流动性收紧:美元基金对国内科技企业的投资额度同比下降40%(2023年数据),导致中小型互联网企业普遍冻结HC,体现在招聘市场上出现"大厂锁HC、中厂砍预算、小厂不招人"的倒金字塔结构。

  3. 合规成本转嫁:GDPR、数据安全法等法规实施后,企业更倾向招募具备数据治理+业务开发复合能力的人才,对传统Java开发者的技术要求从CRUD扩展到安全架构设计层面。

二、行业收缩引发的"技术栈通胀"现象

  1. 互联网流量红利见顶:电商、社交等传统领域新项目减少,存量业务对开发者的要求从"快速迭代"转向"降本增效",一个典型现象是:

    • 2023年Java岗位JD中"微服务优化"出现频率同比上升57%

    • "JVM调优"要求从高级岗下沉至3年经验岗位

    • 单元测试覆盖率成为硬性指标的企业增长32%

  2. 金融科技去杠杆:银行系科技子公司招聘量较峰值下降约35%,但保留的岗位普遍要求:

    • 分布式事务(Seata)+ 监管报送系统开发经验

    • 国产化替代能力(如从WebLogic迁移到TongWeb)

    • 既要懂传统核心系统又要会大数据风控

  3. 传统企业数字化转型遇冷:制造业IT预算削减导致项目型招聘减少,倒逼求职者需要:

    • 掌握低代码平台二次开发(如用JeecgBoot做快速交付)

    • 兼具工控系统对接经验(OPC UA协议等)

    • 能适应驻场开发的"全栈实施工程师"角色

三、AI普及引发的技能迁移压力

  1. 工具链革命

    • GitHub Copilot使基础代码编写效率提升35%,导致企业减少初级岗位招聘

    • 面试中增加"AI结对编程"测试环节(如用ChatGPT生成代码后进行重构)

    • 要求开发者具备prompt工程能力,典型问题如:"如何用自然语言描述一个分布式锁的实现?"

  2. 架构思维升级

    • 面试考点从Spring源码转向AI工程化(模型服务化、推理优化)

    • 混合架构经验成加分项:例如在传统订单系统中集成智能推荐模块

    • 需要理解AI基础设施(向量数据库、模型监控等)

  3. 开发范式转变

    • 单测编写需考虑模型不确定性(如用Diffblue生成测试用例)

    • 事务管理要适应AI服务的最终一致性

    • 性能优化重点转向模型推理资源调度

四、市场供需失衡下的"全栈化生存"

  1. 技术栈的俄罗斯套娃现象

    • Java基础岗要求附带Python数据分析能力(Pandas+可视化)

    • 微服务开发需要掌握K8s故障诊断(而不仅是简单部署)

    • 前端要求从Thymeleaf扩展到Vue3+TS生态

  2. 垂直领域知识溢价

    • 医疗行业:需熟悉HL7/FHIR标准

    • 物流行业:要求了解路径优化算法

    • 能源行业:需具备时序数据处理经验

  3. 性价比博弈

    • 企业用30k预算寻找能替代原有"Java+前端+运维"三人组的人才

    • 对云原生能力的考核点细化到istio流量治理层面

    • 要求提供个人技术博客/GitHub作为能力证明

突围建议(Java开发者视角)

  1. 构建T型能力结构

    • 纵深:深挖JVM底层机制(如ZGC原理、GraalVM应用)

    • 横向:掌握AI工程化基础(LangChain、向量检索)

  2. 打造场景化解决方案能力

    • 将SpringCloud实践升级为云原生成本优化方案

    • 在传统业务系统中设计智能增强点(如用RAG实现知识库问答)

  3. 建立技术影响力杠杆

    • 通过开源贡献证明工程能力(如参与Spring生态项目)

    • 用技术博客展示复杂问题解决能力(如大促期间GC调优实录)

当前市场本质是行业周期与技术革命的叠加态,建议开发者采取"垂直深耕+弹性适配"策略,将Java技术栈作为基础能力底座,向智能化、垂直化、工程效能三个方向进行能力延伸,在提升技术深度的同时保持对新趋势的敏感度。

喜欢的朋友,可以异步我的公众号(codingba),我们一起探讨关于技术、关于人生!

import requests import parsel import re import os import time def change(content): """解密字体加密""" # 看到这里不要慌,后面有教大家如何去生产对应的解码 word_data = {58344: 'd', 58345: '在', 58346: '主', 58347: '特', 58348: '家', 58349: '军', 58350: '然', 58351: '表', 58352: '场', 58353: '4', 58354: '要', 58355: '只', 58356: 'v', 58357: '和', 58359: '6', 58360: '别', 58361: '还', 58362: 'g', 58363: '现', 58364: '儿', 58365: '岁', 58368: '此', 58369: '象', 58370: '月', 58371: '3', 58372: '出', 58373: '战', 58374: '工', 58375: '相', 58376: 'o', 58377: '男', 58378: '直', 58379: '失', 58380: '世', 58381: 'f', 58382: '都', 58383: '平', 58384: '文', 58385: '什', 58386: 'v', 58387: 'o', 58388: '将', 58389: '真', 58390: 't', 58391: '那', 58392: '当', 58394: '会', 58395: '立', 58396: '些', 58397: 'u', 58398: '是', 58399: '十', 58400: '张', 58401: '学', 58402: '气', 58403: '大', 58404: '爱', 58405: '两', 58406: '命', 58407: '全', 58408: '后', 58409: '东', 58410: '性', 58411: '通', 58412: '被', 58413: '1', 58414: '它', 58415: '乐', 58416: '接', 58417: '而', 58418: '感', 58419: '车', 58420: 'l', 58421: '公', 58422: '了', 58423: '常', 58424: '以', 58425: '何', 58426: '可j', 58427: '话', 58428: '先', 58429: 'p', 58430: 'i', 58431: '4', 58432: '轻', 58433: 'm', 58434: '士', 58435: 'w', 58436: '着', 58437: '变', 58438: '尔', 58439: '快', 58440: 'l', 58441: '个', 58442: '说', 58443: '少', 58444: '色', 58445: '里', 58446: '安', 58447: '花', 58448: '远', 58449: '7', 58450: '难', 58451: '师', 58452: '放', 58453: 't', 58454: '报', 58455: '认', 58456: '面', 58457: '道', 58458: 's', 58460: '克', 58461: '地', 58462: '度', 58463: 'l', 58464: '好', 58465: '机', 58466: 'u', 58467: '民', 58468: '写', 58469: '把', 58470: '万', 58471: '同', 58472: '水', 58473: '新', 58474: '没', 58475: '书', 58476: '电', 58477: '吃', 58478: '像', 58479: '斯', 58480: '5', 58481: '为', 58482: 'y', 58483: '白', 58484: '几', 58485: '日', 58486: '教', 58487: '看', 58488: '但', 58489: '第', 58490: '加', 58491: '候', 58492: '作', 58493: '上', 58494: '拉', 58495: '住', 58496: '有', 58497: '法', 58498: 'r', 58499: '事', 58500: '应', 58501: '位', 58502: '利', 58503: '你', 58504: '声', 58505: '身', 58506: '国', 58507: '问', 58508: '马', 58509: '女', 58510: '他', 58511: 'y', 58512: '比', 58513: '父', 58514: 'x', 58515: 'a', 58516: 'h', 58517: 'n', 58518: 's', 58519: 'x', 58520: '边', 58521: '美', 58522: '对', 58523: 'f所', 58524: '金', 58525: '活', 58526: '回', 58527: '意', 58528: '到', 58529: 'z', 58530: '从', 58531: 'j', 58532: '知', 58533: '又', 58534: '内', 58535: '因', 58536: '点', 58537: 'q', 58539: '定', 58540: '8', 58541: 'R', 58542: 'b', 58543: '正', 58544: '或', 58545: '夫', 58546: '向', 58547: '德', 58548: '听', 58549: '更', 58551: '得', 58552: '告', 58553: '并', 58554: '本', 58555: 'q', 58556: '过', 58557: '记', 58558: 'l', 58559: '让', 58560: '打', 58561: 'f', 58562: '人', 58563: '就', 58564: '者', 58565: '去', 58566: '原', 58567: '满', 58568: '体', 58569: '做', 58570: '经', 58571: 'K', 58572: '走', 58573: '如', 58574: '孩', 58575: 'c', 58576: 'g', 58577: '给', 58578: '使', 58579: '物', 58581: '最', 58582: '笑', 58583: '部', 58585: '员', 58586: '等', 58587: '受', 58588: 'k', 58589: '行', 58591: '条', 58592: '果', 58593: '动', 58594: '光', 58595: '门', 58596: '头', 58597: '见', 58598: '往', 58599: '自', 58600: '解', 58601: '成', 58602: '处', 58603: '天', 58604: '能', 58605: '于', 58606: '名', 58607: '其', 58608: '发', 58609: '总', 58610: '母', 58611: '的', 58612: '死', 58613: '手', 58614: '入', 58615: '路', 58616: '进', 58617: '心', 58618: '来', 58619: 'h', 58620: '时', 58621: '力', 58622: '多', 58623: '开', 58624: '已', 58625: '许', 58626: 'd', 58627: '至', 58628: '由', 58629: '很', 58630: '界', 58631: 'n', 58632: '小', 58633: '与', 58634: 'z', 58635: '想', 58636: '代', 58637: '么', 58638: '分', 58639: '生', 58640: '口', 58641: '再', 58642: '妈', 58643: '望', 58644: '次', 58645: '西', 58646: '风', 58647: '种', 58648: '带', 58649: 'j', 58651: '实', 58652: '情', 58653: '才', 58654: '这', 58656: 'e', 58657: '我', 58658: '神', 58659: '格', 58660: '长', 58661: '觉', 58662: '间', 58663: '年', 58664: '眼', 58665: '无', 58666: '不', 58667: '亲', 58668: '关', 58669: '结', 58670: '0', 58671: '友', 58672: '信', 58673: '下', 58674: '却', 58675: '重', 58676: '己', 58677: '老', 58678: '2', 58679: '音', 58680: '字', 58681: 'm', 58682: '呢', 58683: '明', 58684: '之', 58685: '前', 58686: '高', 58687: 'p', 58688: 'b', 58689: '目', 58690: '太', 58691: 'e', 58692: '9', 58693: '起', 58694: '棱', 58695: '她', 58696: '也', 58697: 'w', 58698: '用', 58699: '方', 58700: '子', 58701: '英', 58702: '每', 58703: '理', 58704: '便', 58705: '四', 58706: '数', 58707: '期', 58708: '中', 58709: 'c', 58710: '外', 58711: '样', 58712: 'a', 58713: '海', 58714: '们', 58715: '任', 58538: '三', 58590: '一'} result = '' for i in content: code = ord(i) if code in word_data: result += word_data[code] else: result += i return result # 请求头 headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0" , # 下面会带大家如何去,需要自行去替换 } # 目标小说目录页链接 lianjie: str = input("小说链接:") link = lianjie # 下面会带大家如何去,需要自行去替换 link_response = requests.get(url=link, headers=headers) link_data = link_response.text # 提取小说名称 name = re.findall('"bookName":"(.*?)",', link_data)[0] valid_name = re.sub(r'[\\/:*?"<>|]', '', name) os.makedirs(valid_name, exist_ok=True) # 提取章节ID列表(保持原有 chapter_id_list 逻辑) chapter_id_list = re.findall('<a href="/reader/(\\d+)" class="chapter-item-title"', link_data)[1:] # 遍历章节 for chapter_id in chapter_id_list: url = f'https://fanqienovel.com/reader/{chapter_id}' try: response = requests.get(url=url, headers=headers, timeout=10) response.raise_for_status() # 检查HTTP状态码 html = response.text # 解析章节标题 selector = parsel.Selector(html) title = selector.css('.muye-reader-title::text').get() if not title: print(f"⚠️ 章节 {chapter_id} 未到标题,跳过...") continue # 清理标题非法字符 valid_title = re.sub(r'[\\/:*?"<>|]', '', title) # 解析正文内容 content_list = selector.css('.muye-reader-content p::text').getall() content = '\n\n'.join(content_list) new_content = change(content) # 写入章节文件 file_path = os.path.join(valid_name, f'{valid_title}.txt') with open(file_path, 'w', encoding='utf-8') as f: f.write(title + '\n\n') f.write(new_content) print(f"✅ 已保存章节: {valid_title}") time.sleep(1) # 避免频繁请求 except Exception as e: print(f"❌ 章节 {chapter_id} 爬取失败: {str(e)}") continue print(f'《{valid_name}》共 {len(chapter_id_list)} 章节已保存完成') 小说链接:https://fanqienovel.com/page/7351282372152675353?force_mobile=1 《什么,梦中的娘子都是真的》共 0 章节已保存完成 进程已结束,退出代码为 0
07-01
<think>我们面对的问题:爬取小说章节时返回空列表,章节数量为0。可能的原因:1.请求的章节列表页面返回的内容与预期不符(可能是动态加载、反爬虫机制等)。2.解析章节列表的代码有误(如XPath、CSS选择器表达式错误)。3.网站结构发生变化,导致原有的解析方式失效。4.请求头(headers)设置不当,服务器拒绝响应正确内容。根据引用[3]和[4]的经验,当爬取返回空列表时,需要检查: -请求是否成功(响应状态码)-获取的网页内容是否包含目标数据(可能为动态加载,需要查看网页源码) -解析表达式是否正确(通过对比浏览器中元素的实际XPath和代码中的XPath)解决步骤:1. **确认请求是否成功**:打印响应状态码和响应内容的前若干字符,确认是否获取到了正确的页面。2.**检查网页内容**:将获取的网页内容保存为html文件,然后在浏览器中打开,检查是否包含章节列表。如果不包含,可能是动态加载(JavaScript渲染)或反爬虫措施(如验证User-Agent)。3.**检查解析表达式**:使用浏览器的开发者工具(如Chrome的检查功能)查看章节列表的HTML结构,并测试XPath或CSS选择器表达式。4. **处理动态加载**:如果章节列表是动态加载的,可能需要使用Selenium或分析Ajax请求。但首先尝试使用requests模拟请求。5.**设置请求头**:模拟浏览器访问,设置User-Agent等请求头字段。6.**处理反爬虫**:如果网站有反爬虫机制,可能需要使用代理、设置请求间隔、使用cookies等。具体操作:步骤1:打印状态码和响应内容```pythonimport requestsurl ="https://example.com/novel"#替换为目标小说目录页的URLheaders ={'User-Agent': 'Mozilla/5.0(Windows NT10.0; Win64;x64) AppleWebKit/537.36(KHTML,like Gecko)Chrome/91.0.4472.124Safari/537.36'} response= requests.get(url, headers=headers) print("状态码:", response.status_code)#打印前1000个字符,避免太长print(response.text[:1000])```步骤2:如果响应内容中确实包含章节列表,则检查解析代码。例如,使用XPath解析章节列表:```pythonfromlxmlimport etreehtml =etree.HTML(response.text)#假设章节列表的XPath为'//div[@class="list"]/a'chapter_list =html.xpath('//div[@class="list"]/a')print("章节数量:",len(chapter_list)) ```如果打印的章节数量为0,则说明XPath表达式可能写错了。步骤3:在浏览器中打开目标页面,右键点击章节列表元素,选择“检查”,然后右键点击对应的HTML元素,选择“Copy”->“Copy XPath”,尝试使用这个XPath。但注意,浏览器复制的XPath可能过长且依赖具体结构,需适当简化。步骤4:如果响应内容中不包含章节列表(即步骤1打印的内容中没有章节信息),则可能是动态加载。此时,需要:-在浏览器中打开网页,按F12打开开发者工具,切换到“网络”(Network)选项卡,刷新页面,查看XHR请求(Ajax请求)。到包含章节列表数据的请求,然后模拟这个请求。-如果数据是JSON格式,则可以直接解析JSON。步骤5:如果网站需要登录或使用cookies,则需要在请求中添加cookies。示例代码(模拟Ajax请求):假设通过分析发现章节数据是通过一个Ajax请求获取的,URL为:https://example.com/novel/chapters?bookId=123则代码改为:```pythonurl= "https://example.com/novel/chapters?bookId=123" response= requests.get(url, headers=headers) #如果返回的是JSONdata =response.json() chapters= data['chapters']#根据实际JSON结构调整```步骤6:如果以上方法都无效,可以考虑使用Selenium模拟浏览器:```pythonfromselenium importwebdriverfromselenium.webdriver.chrome.optionsimport Optionschrome_options =Options()chrome_options.add_argument('--headless')#无头模式driver =webdriver.Chrome(options=chrome_options) driver.get(url) #等待页面加载完成(可设置显式等待) fromselenium.webdriver.common.byimport Byfromselenium.webdriver.support.ui importWebDriverWaitfrom selenium.webdriver.support importexpected_conditions asECtry:element= WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH,'//div[@class="list"]/a')))#获取整个页面的HTMLhtml =driver.page_sourcefinally:driver.quit() #然后用lxml解析html```注意事项:-使用Selenium需要安装对应的WebDriver(如ChromeDriver)。-无头模式可能被一些网站识别,可以设置更多的浏览器参数来模拟真实浏览器。总结:先通过打印响应内容判断问题出在请求阶段还是解析阶段,再针对性地解决。如果问题仍然存在,请提供目标网站URL和当前代码,以便进一步分析。参考引用[3][^3]和[4][^4]中提到的解决思路:当返回空列表时,检查实际获取的网页内容是否包含目标数据,以及解析表达式是否正确。 §§相关问题§§1.如何用Python处理动态加载(Ajax)的网页数据? 2.如何设置请求头(headers)和代理(proxies)来避免反爬虫? 3.使用Selenium时如何避免被检测到是自动化工具?</think>## Python爬虫爬取小说章节返回空列表的解决方法 当使用Python爬取小说章节时返回空列表,通常是由于以下原因导致的。我将结合您的错误信息和引用内容,提供系统解决方案: ### 问题原因分析 1. **目标网站结构变化**:网页结构可能已更新,原有XPath/CSS选择器失效(引用[3][^3]) 2. **动态加载内容**:章节列表可能通过JavaScript动态加载(引用[2][^2]) 3. **反爬虫机制**:网站可能检测到爬虫行为,返回空内容(引用[4][^4]) 4. **解析逻辑错误**:XPath表达式或解析方法不匹配实际HTML结构 ### 解决方案步骤 #### 1. 验证请求是否成功 ```python import requests from lxml import etree url = "https://www.xbiquge.la/15/15409/" # 替换实际小说目录页URL headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } response = requests.get(url, headers=headers) print("状态码:", response.status_code) # 应返回200 print("响应长度:", len(response.text)) # 检查内容是否为空 ``` #### 2. 检查实际获取的HTML内容 ```python # 保存获取的HTML用于分析 with open('page.html', 'w', encoding='utf-8') as f: f.write(response.text) ``` 打开保存的HTML文件,检查章节列表是否存在于原始HTML中(引用[4][^4]) #### 3. 更新解析逻辑(XPath示例) ```python # 正确示例:适应常见小说网站结构 html = etree.HTML(response.text) # 通用章节列表选择器 chapters = html.xpath('//div[@id="list"]//dd/a/text()') # 章节标题 links = html.xpath('//div[@id="list"]//dd/a/@href') # 章节链接 print(f"到章节数: {len(chapters)}") ``` #### 4. 处理动态加载内容(使用Selenium) 当章节列表通过AJAX加载时: ```python from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_argument('--headless') # 无头模式 driver = webdriver.Chrome(options=chrome_options) driver.get(url) # 等待章节加载 driver.implicitly_wait(5) # 获取渲染后的HTML html = driver.page_source driver.quit() # 解析章节 parsed_html = etree.HTML(html) chapters = parsed_html.xpath('//div[@class="chapter-list"]//a/text()') ``` #### 5. 绕过反爬虫机制 ```python # 增加请求头真实性 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Connection': 'keep-alive' } # 使用会话保持 session = requests.Session() response = session.get(url, headers=headers) # 添加随机延迟 import time import random time.sleep(random.uniform(1, 3)) ``` #### 6. 验证解析结果 ```python if len(chapters) == 0: # 备用选择器方案 chapters = html.xpath('//*[contains(@class, "chapter")]//a/text()') if len(chapters) == 0: print("警告: 仍获取0章节,请检查:") print("- 网页结构是否变更") print("- 是否触发反爬机制") print("- 尝试使用浏览器开发者工具验证XPath") ``` ### 关键检查点 1. 在浏览器中**右键检查**章节列表元素,验证XPath 2. 查看**网络请求**中是否有单独加载章节数据的API(引用[2][^2]) 3. 检查HTML中是否包含**章节数据但被注释**(如`<!-- 章节列表 -->`) 4. 确认目标网站**没有使用iframe**加载章节内容 ### 完整工作流程 ```mermaid graph TD A[发起请求] --> B{状态码200?} B -->|是| C[检查HTML内容] B -->|否| D[检查URL/头信息/代理] C --> E{章节存在?} E -->|是| F[使用XPath解析] E -->|否| G[检查动态加载] G --> H[使用Selenium] F --> I[获取章节数据] H --> I I --> J{数据有效?} J -->|是| K[保存结果] J -->|否| L[尝试备用选择器] ``` 通过以上方法,90%的小说章节空列表问题都能解决。如果问题仍然存在,请提供具体网站URL,我可以针对该站点给出定制方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值