Selenium爬虫中zfill方法作用及爬取提前终止问题排查
zfill()方法作用与Naukri爬虫异常排查
zfill()方法的基础作用
Python中str.zfill(width)的作用是在字符串左侧补0,将字符串填充到指定长度。这段代码里传入参数2,就是把数字转成固定两位长度的字符串:1转成'01'、9转成'09',10及以上的数字本身长度为2,不会补0,直接返回'10'、'20'。
两个异常现象的根因
这段代码的核心隐患是用字符串全量替换的方式更新XPath中的岗位索引:Python的str.replace()会替换字符串中所有匹配的子串,而不是只替换岗位列表的索引位置,zfill的存在本质是在给这个不严谨的写法补漏洞。
移除第一个zfill仅爬3条就终止的原因
- 初始XPath中除了岗位列表的索引位,还有固定路径的数字:经验字段对应
li[1]、薪资字段对应li[2]。 - 去掉第一个zfill后,岗位索引是
'1'、'2'、'3'这类单个数字,和固定路径里的1、2完全重合,替换时会把li标签的索引也一起改掉:- 爬第1条岗位时,替换初始索引
'0'为'1',li标签的数字没被改动,XPath正常,能拿到数据。 - 爬第2条岗位时,替换旧索引
'1'为'2',会把li[1]的1也改成2,经验字段的XPath直接指向薪资节点,虽然数据错位,但元素存在,不会报错。 - 爬第3条岗位时,替换旧索引
'2'为'3',会把li标签的索引也改成3,而每个岗位卡片下只有2个li标签(经验、薪资),li[3]根本不存在,触发wait.until()的20秒超时。后续循环li的索引会被改成4、5...,永远定位不到元素,每次等待20秒才走异常分支,速度极慢,看起来就像循环终止。
- 爬第1条岗位时,替换初始索引
- 保留第一个zfill时,1-9的索引是
'01'、'02'这类带前导零的两位字符串,和固定路径里li[1]、li[2]的单个数字完全不匹配,替换时只会改岗位列表的索引位,不会碰固定路径,XPath始终合法。
移除第二个zfill无明显异常的原因
第二个zfill是给存储上一次索引值的index变量赋值用的。去掉它之后,虽然替换时会给XPath里的数字多加前导零(比如把li[1]改成li[02]、岗位索引改成[002]),但XPath语法本身不介意数字前导零,[002]和[2]的定位效果完全一致,所以程序运行表面没有异常,只是XPath字符串里有冗余的前导零,逻辑上存在隐患但没触发功能问题。
最优解决方案
原来的字符串替换更新XPath的写法非常脆弱,不需要靠zfill补漏洞,直接在每次循环时用f字符串重新生成当前岗位的XPath即可,从根源上避免误替换问题,代码更简洁健壮:
# 删除循环外提前定义title_xpath、link_xpath等变量的代码 while i < count: for j in range(20): current_idx = new_index # 每次循环直接拼接生成当前岗位的完整XPath,无需做字符串替换 base_xpath = f'(//*[@class="jobTuple bgWhite br4 mb-8"])[{current_idx}]' title_xpath = f'{base_xpath}/div/div/a' link_xpath = title_xpath comp_xpath = f'{base_xpath}/div/div/div/a' exp_xpath = f'{base_xpath}/div/div/ul/li[1]/span' salary_xpath = f'{base_xpath}/div/div/ul/li[2]/span' # 下方元素定位、写入CSV逻辑和原代码一致 try: heading = wait.until(EC.presence_of_element_located((By.XPATH, title_xpath))).text print(heading) except: heading = "Not Available" try: link = wait.until(EC.presence_of_element_located((By.XPATH, link_xpath))).get_attribute('href') print(link) except: link = "Not Available" try: subheading = wait.until(EC.presence_of_element_located((By.XPATH, comp_xpath))).text print(subheading) except: subheading = "NULL" try: experience = wait.until(EC.presence_of_element_located((By.XPATH, exp_xpath))).text print(experience) except: experience = "Not Available" try: salary = wait.until(EC.presence_of_element_located((By.XPATH, salary_xpath))).text print(salary) except: salary = "Not Disclosed" new_index += 1 i += 1 print(f"{i}.") csv_writer.writerow([heading, subheading, link, experience, salary]) if i >= count: break if i >= count: break wait.until(EC.element_to_be_clickable((By.XPATH, '//*[text() = "Next"]'))).click() new_index = 1
这种写法完全不需要维护temp_index、index这类中间变量,也不需要zfill做格式兼容,不会出现替换改坏XPath的问题。
内容的提问来源于stack exchange,提问作者Hatake Itachi
相关产品推荐
相关产品推荐

