基于XPath的Python爬虫实现【零基础教学】 1.第三方库安装2.自动登录3.数据提取4.保存到csv5.完整代码1. 第三方库安装安装的第三方库主要有以下几个import os import time import pandas as pd from playwright.sync_api import sync_playwright from lxml import html2.自动登录跳转到目标页面通过输入框的属性定位到输入框自动填入账号密码登录def auto_login(page, url, username, password): 负责访问页面并执行登录操作 print(f1. 正在访问: {url}) page.goto(url) # 跳转到目标页面 print( - 正在刷新页面...) page.reload() # 刷新页面 page.wait_for_load_state(networkidle) print( - 尝试自动登录...) try: # 填写账号,通过输入框的palceholder账户属性定位到它 page.fill(input[placeholder账户], username) # 填写密码,通过输入框的palceholder密码属性定位到它 page.fill(input[placeholder密码], password) # 点击登录 page.click(button.login-submit) # 等待跳转完成 page.wait_for_load_state(networkidle) print( - 登录操作完成) except Exception as e: print(f - [提示] 自动登录跳过或遇到问题可能已登录: {e})3.数据提取设置当前页面为400条/页定位到产品标签提取产品的代码名称价格完成后当前页后点击下一页按钮def extract_data(page): 负责解析页面 HTML自动翻页并提取所有目标数据 print(2. 正在等待产品列表加载...) page.wait_for_selector(.code, timeout30000) # # 切换每页显示条数 # print( - 正在设置每页显示 400 条请稍候...) try: # 1. 找下拉框找页面上 placeholder 为 请选择 的 input 框并取最后一个通常底部分页在最后 page.locator(input[placeholder请选择]).last.click() time.sleep(1) # 等待下拉动画展开 # 2. 找选项使用精准的文字匹配选中 400条/页 page.locator(li.el-select-dropdown__item, has_text400条/页).click() # 3. 等待网络请求完成加载出 400 条数据 page.wait_for_load_state(networkidle) time.sleep(3) # 400条数据渲染 DOM 需要时间多等一下 print( - 页面条数切换成功) except Exception as e: print(f - [警告] 切换 400条/页 失败将按默认条数抓取: {e}) all_data_list [] page_num 1 # 开启循环翻页 while True: # 设置获取前10页数据 if page_num 10: print(f\n - [完成] 已达到设定的 {page_num - 1} 页上限主动停止抓取。) break print(f\n - 开始提取第 {page_num} 页数据...) tree html.fromstring(page.content()) # 通过xpath获取到指定的条目通过网页HTML可以发现通过div classproduct-card... 可以定位到产品条目 items tree.xpath(//div[contains(class, product-card)]) current_page_count 0 for item in items: # 找一个 class 包含 code 的 div code item.xpath(.//div[contains(class, code)]/title) # 找一个 class 包含 title 的 div name item.xpath(.//div[contains(class, title)]/title) # 找一个 class 包含 price overflow 的 div price item.xpath(.//div[contains(class, price overflow)]/i/text()) # 处理编号强制 Excel 识别为文本 extracted_code code[0].strip() if code else 无 if extracted_code ! 无: extracted_code extracted_code \t all_data_list.append({ 编号: extracted_code, 名称: name[0].strip() if name else 无, 价格: price[0].strip() if price else 无 }) current_page_count 1 print(f - 第 {page_num} 页提取完成获取到 {current_page_count} 个产品。) # # 翻页逻辑判定 # # 在当前网页中去寻找一个 class为 btn-next 的元素并把它记作 next_button next_button page.locator(.btn-next) # 判定 A无下一页按钮 if next_button.count() 0: print( - [完成] 未找到“下一页”按钮所有页面抓取完毕。) break # 判定 B下一页按钮被禁用到达最后一页 is_disabled_attr next_button.get_attribute(disabled) is not None has_disabled_class is-disabled in (next_button.get_attribute(class) or ) if is_disabled_attr or has_disabled_class: print( - [完成] “下一页”按钮已变为不可点击状态到达最后一页。) break print( - 点击下一页等待数据加载...) next_button.click() # 关键等待等待网络请求并硬休眠防止拿到旧数据 page.wait_for_load_state(networkidle) time.sleep(2) page_num 1 final_pages page_num - 1 if page_num 10 else page_num print(f\n 全部提取任务完成共跨越 {final_pages} 页累计获取 {len(all_data_list)} 个产品。) return all_data_list重点介绍一下提取的核心代码使用的是XPathXML 路径语言3.1 提取编码codecode item.xpath(.//div[contains(class, code)]/title)寻找目标找一个class包含code的div终极动作/title符号代表“提取属性”。这句话的意思是找到这个 div 后不要它里面的文字我要把它身上的title属性的值抠下来。3.2 提取名称namename item.xpath(.//div[contains(class, title)]/title)寻找目标找一个class包含title的div。终极动作/title和上面一样提取title属性的值。假设网页源码是div classtitle title2000万像素相机2000万像.../div提取结果2000万像素相机3.3 提取价格priceprice item.xpath(.//div[contains(class, price overflow)]/i/text())寻找目标找一个class包含price overflow的div。终极动作/i/text()/i单斜杠i代表找到这个 div 之后直接往下一层找它的“亲儿子”i标签。/text()代表提取夹在这个i和/i标签中间的纯文本内容。假设网页源码是div classprice overflowi199.50/i/div提取结果199.504.保存到csv提取到的数据将会保存在当前程序运行目录下def save_to_csv(data_list, filenameproduct_data.csv): 将提取到的数据保存到当前运行目录 if not data_list: print(\n3. [提示] 没有数据可保存跳过导出步骤。) return print(\n3. 正在整理数据并导出...) current_dir os.getcwd() save_path os.path.join(current_dir, filename) # 导出为 utf-8-sig 防止 Excel 中文乱码 df pd.DataFrame(data_list) df.to_csv(save_path, indexFalse, encodingutf-8-sig) print(f - 完美收工文件已存放在: {save_path})5. 完整代码import os import time import pandas as pd from playwright.sync_api import sync_playwright from lxml import html # # 模块 1自动登录 # def auto_login(page, url, username, password): 负责访问页面并执行登录操作 print(f1. 正在访问: {url}) page.goto(url) print( - 正在刷新页面...) page.reload() # 确保刷新后页面资源加载完毕 page.wait_for_load_state(networkidle) print( - 尝试自动登录...) try: page.fill(input[placeholder账号], username) page.fill(input[placeholder密码], password) page.click(button.login-submit) page.wait_for_load_state(networkidle) print( - 登录操作完成) except Exception as e: print(f - [提示] 自动登录跳过或遇到问题可能已登录: {e}) # # 模块 2数据提取 (含精准下拉框操作与翻页) # def extract_data(page): 负责解析页面 HTML自动翻页并提取所有目标数据 print(2. 正在等待产品列表加载...) page.wait_for_selector(.code, timeout30000) # # 切换每页显示条数 (精准版) # print( - 正在设置每页显示 400 条请稍候...) try: # 1. 找下拉框找页面上 placeholder 为 请选择 的 input 框并取最后一个通常底部分页在最后 page.locator(input[placeholder请选择]).last.click() time.sleep(1) # 等待下拉动画展开 # 2. 找选项使用精准的文字匹配选中 400条/页 page.locator(li.el-select-dropdown__item, has_text400条/页).click() # 3. 等待网络请求完成加载出 400 条数据 page.wait_for_load_state(networkidle) time.sleep(3) # 400条数据渲染 DOM 需要时间多等一下 print( - 页面条数切换成功) except Exception as e: print(f - [警告] 切换 400条/页 失败将按默认条数抓取: {e}) all_data_list [] page_num 1 # 开启循环翻页 while True: # 限制最多提取 10 页 if page_num 10: print(f\n - [完成] 已达到设定的 {page_num - 1} 页上限主动停止抓取。) break print(f\n - 开始提取第 {page_num} 页数据...) tree html.fromstring(page.content()) items tree.xpath(//div[contains(class, product-card)]) current_page_count 0 for item in items: code item.xpath(.//div[contains(class, code)]/title) name item.xpath(.//div[contains(class, title)]/title) price item.xpath(.//div[contains(class, price overflow)]/i/text()) # 处理编号强制 Excel 识别为文本 extracted_code code[0].strip() if code else 无 if extracted_code ! 无: extracted_code extracted_code \t all_data_list.append({ 编号: extracted_code, 名称: name[0].strip() if name else 无, 价格: price[0].strip() if price else 无 }) current_page_count 1 print(f - 第 {page_num} 页提取完成获取到 {current_page_count} 个产品。) # # 翻页逻辑判定 # next_button page.locator(.btn-next) # 判定 A无下一页按钮 if next_button.count() 0: print( - [完成] 未找到“下一页”按钮所有页面抓取完毕。) break # 判定 B下一页按钮被禁用到达最后一页 is_disabled_attr next_button.get_attribute(disabled) is not None has_disabled_class is-disabled in (next_button.get_attribute(class) or ) if is_disabled_attr or has_disabled_class: print( - [完成] “下一页”按钮已变为不可点击状态到达最后一页。) break print( - 点击下一页等待数据加载...) next_button.click() # 关键等待等待网络请求并硬休眠防止拿到旧数据 page.wait_for_load_state(networkidle) time.sleep(2) page_num 1 final_pages page_num - 1 if page_num 10 else page_num print(f\n 全部提取任务完成共跨越 {final_pages} 页累计获取 {len(all_data_list)} 个产品。) return all_data_list # # 模块 3保存到 CSV # def save_to_csv(data_list, filenameproduct_data.csv): 将提取到的数据保存到当前运行目录 if not data_list: print(\n3. [提示] 没有数据可保存跳过导出步骤。) return print(\n3. 正在整理数据并导出...) current_dir os.getcwd() save_path os.path.join(current_dir, filename) # 导出为 utf-8-sig 防止 Excel 中文乱码 df pd.DataFrame(data_list) df.to_csv(save_path, indexFalse, encodingutf-8-sig) print(f - 完美收工文件已存放在: {save_path}) # # 主程序控制逻辑 # def main(): # ---- 运行前请在此确认你的配置信息 ---- TARGET_URL 你的目标网址 USERNAME 你的账号 PASSWORD 你的密码 # 请确保此路径指向你电脑真实的 Chrome 浏览器路径 CHROME_PATH rC:/xxx/Google/Chrome/Application/chrome.exe # ---------------------------------------- with sync_playwright() as p: print(正在启动指定的本地 Chrome 浏览器...) # 启动本地浏览器 context p.chromium.launch_persistent_context( user_data_dir./user_data, # 保持 Cookie 与登录状态 executable_pathCHROME_PATH, headlessFalse, # 如果想要后台运行改为 True viewport{width: 1280, height: 720} ) page context.new_page() try: # 1. 自动登录 auto_login(page, TARGET_URL, USERNAME, PASSWORD) # 2. 提取数据 (涵盖条数切换与翻页) product_data extract_data(page) # 3. 保存数据 save_to_csv(product_data, filename产品全部数据.csv) except Exception as e: print(f\n[错误] 程序运行中途报错了: {e}) finally: print(\n程序执行完毕。浏览器已保持开启状态你可以手动关闭它。) if __name__ __main__: main()