公司动态

Selenium模拟登录淘宝爬取商品与评论数据实战指南

📅 2026/7/24 15:05:47
Selenium模拟登录淘宝爬取商品与评论数据实战指南
1. 项目概述与核心价值最近在数据分析和市场调研的圈子里聊到电商数据获取Selenium模拟登录淘宝爬取商品信息这个话题总是绕不开。这不仅仅是一个简单的技术练习它背后对应的是真实业务场景下的刚需比如竞品价格监控、用户评论情感分析、爆款商品趋势预测甚至是自动化比价工具的底层实现。很多新手一上来就想直接抓取淘宝页面结果发现要么是数据加载不出来要么就是立刻被风控机制拦截根本走不通。这恰恰说明了模拟真实用户行为登录的重要性——它不再是“可选项”而是“必选项”。这个项目的核心就是利用Selenium这个浏览器自动化工具完整地模拟一个真实用户在电脑前打开浏览器、登录淘宝、搜索商品、浏览详情并获取数据特别是动态加载的评论的全过程。它解决的痛点非常明确对抗现代网页日益复杂的反爬策略如JavaScript渲染、用户行为验证、登录态校验。通过这个实战你不仅能学会Selenium的基本操作更能深入理解如何让程序“伪装”得更像人从而稳定、持续地获取到那些通过简单请求无法拿到的宝贵数据。无论你是数据分析师、产品经理还是对电商自动化感兴趣的程序员这套方法都能为你打开一扇新的大门。2. 环境搭建与核心工具选型解析工欲善其事必先利其器。一个稳定、高效且易于调试的环境是项目成功的第一步。这里我们不追求最炫技的配置而是追求最稳定、最贴近真实用户且最容易排查问题的方案。2.1 浏览器与驱动选择为什么是Chrome 手动管理驱动市面上主流的浏览器驱动有ChromeDriver、GeckoDriverFirefox和EdgeDriver。我强烈推荐使用Google Chrome浏览器配合ChromeDriver。原因有三点首先Chrome的市场占有率最高其用户行为模式是反爬系统重点模拟和“白名单”化的对象用Chrome本身就能降低一部分行为异常的风险。其次Chrome DevTools Protocol (CDP) 功能强大后续我们进行高级反反爬如绕过WebDriver检测时会用到它。最后Chrome的社区支持和资料是最丰富的遇到问题更容易找到解决方案。关于ChromeDriver的安装我强烈反对使用某些自动化包管理工具去“智能”匹配版本。淘宝等大型网站对浏览器版本非常敏感驱动与浏览器版本不匹配是导致Session not created错误的头号元凶。最稳妥的做法是打开Chrome在地址栏输入chrome://version/查看第一行的“Google Chrome”版本号例如128.0.6613.138。访问ChromeDriver的官方镜像站如https://chromedriver.storage.googleapis.com/index.html下载与你的Chrome主版本号即128完全一致的驱动版本。将下载的chromedriver.exeWindows或chromedriverMac/Linux放在一个固定的、已加入系统环境变量PATH的目录中或者直接在代码中指定其绝对路径。注意淘宝/天猫的登录页面和主站经常更新可能会强制要求较新版本的浏览器。如果你的脚本某天突然无法登录第一个检查点就应该是浏览器和驱动版本是否过旧。2.2 Python环境与依赖库清单建议使用Python 3.8及以上版本。创建一个独立的虚拟环境venv或conda来管理依赖是个好习惯避免包冲突。核心库只有以下几个但每个都至关重要pip install selenium4.* # 使用4.x版本API更现代稳定 pip install pandas # 用于数据清洗和存储非必须但强烈推荐 pip install webdriver-manager # 可选用于自动管理驱动但生产环境建议手动控制Selenium 4相比旧版本在等待策略、相对定位器等方面有改进我们后续会用到其更优雅的等待方式。pandas不是爬虫必需的但当你处理爬取到的结构化数据如商品列表、评论时它能极大地提升数据清洗和导出到CSV/Excel的效率。2.3 对抗基础反爬Selenium Stealth 与额外参数默认情况下Selenium驱动的浏览器会被网站检测到通过navigator.webdriver属性。淘宝的风控系统对此非常敏感。因此我们的第一个反反爬措施就是在启动浏览器时进行“伪装”。直接使用selenium-stealth库是一个有效方案但更底层、更可控的方式是手动添加实验性选项。这里给出一种综合方案from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options def create_stealth_driver(driver_path): chrome_options Options() # 1. 基础隐身避免自动化特征 chrome_options.add_argument(--disable-blink-featuresAutomationControlled) chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) chrome_options.add_experimental_option(useAutomationExtension, False) # 2. 伪装成普通用户浏览器 chrome_options.add_argument(--user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36) chrome_options.add_argument(--disable-gpu) chrome_options.add_argument(--no-sandbox) # Linux环境下常用 chrome_options.add_argument(--disable-dev-shm-usage) # 解决共享内存问题 # 3. 可选无头模式配置调试时不建议开启 # chrome_options.add_argument(--headlessnew) # 新版无头模式 # 无头模式下需额外伪装因为有些检测会检查窗口大小等 # chrome_options.add_argument(--window-size1920,1080) # 4. 创建驱动 service Service(executable_pathdriver_path) driver webdriver.Chrome(serviceservice, optionschrome_options) # 5. 执行CDP命令覆盖WebDriver属性关键步骤 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); }) return driver这段代码是启动浏览器的核心。关键点在于通过execute_cdp_cmd在页面加载前就注入JavaScript将navigator.webdriver属性重写为undefined这是绕过最常见检测的核心。user-agent设置为一个常见的桌面端Chrome UA避免使用冷门或旧版本。3. 模拟登录淘宝策略、步骤与避坑指南登录是本次实战中最具挑战性的环节。淘宝的登录流程复杂融合了密码登录、扫码登录、滑动验证等多种方式且风控等级极高。3.1 登录流程分析与策略选择访问taobao.com点击“亲请登录”后你会被重定向到登录页面。目前主要有两种方式密码登录需要输入用户名和密码极大概率触发滑动验证码。扫码登录页面显示一个二维码用手机淘宝APP扫码即可登录。对于自动化脚本而言扫码登录是更可行、更稳定的选择。原因如下密码登录不仅要处理加密的密码字段可能涉及动态密钥还要破解或绕过滑动验证码这引入了OCR识别、轨迹模拟等复杂问题成功率低且容易被封。而扫码登录本质上是在等待一个“登录成功”的状态回调我们只需要让程序停留在二维码页面并轮询检查登录状态即可更符合“模拟真人”的操作——真人此时也是拿出手机扫码。因此我们的策略是引导至扫码登录页面等待用户手动扫码程序检测登录成功后再继续执行。3.2 分步实操从访问到登录成功假设我们已经用上文create_stealth_driver函数创建了driver对象。from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time def login_to_taobao(driver): 模拟登录淘宝采用扫码登录方式。 返回登录成功后的driver对象。 print(正在访问淘宝首页...) driver.get(https://www.taobao.com) # 等待页面加载并点击登录链接 # 登录按钮的定位器可能变化需要根据实际情况调整 try: login_link WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.LINK_TEXT, 亲请登录)) ) login_link.click() print(已点击登录链接。) except Exception as e: # 如果找不到文字链接尝试通过类名或ID查找 print(f未找到文字登录链接尝试其他方式: {e}) # 可能需要查看当前页面实际元素进行调整 # 例如driver.find_element(By.CLASS_NAME, site-nav-login).click() # 这里需要你手动打开页面使用开发者工具F12查看元素属性 raise # 关键切换到扫码登录标签页 # 等待登录框加载并找到“扫码登录”的标签或按钮 print(等待登录模态框加载...) time.sleep(3) # 登录页加载可能需要一点时间显式等待有时不如强制等待稳定 # 方法一尝试点击“扫码登录”标签常见 try: qr_tab WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, //div[contains(text(), 扫码登录)])) ) qr_tab.click() print(已切换到扫码登录模式。) except: # 方法二如果页面直接显示了二维码则无需切换 print(未找到显式的扫码登录标签可能已默认显示二维码。) # 等待二维码图片出现 print(等待二维码加载...) try: qr_code_element WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, img[src*qrcode])) # 包含qrcode的图片 ) print(二维码已显示。请打开手机淘宝APP扫码登录。) except Exception as e: print(f未找到二维码元素当前URL: {driver.current_url}) print(可能登录页面结构已更新请手动检查页面元素。) # 可以在这里保存页面截图辅助调试 driver.save_screenshot(login_page.png) raise # 核心轮询检测登录是否成功 print(等待扫码确认...) login_success False max_wait_time 120 # 最大等待2分钟 start_time time.time() while time.time() - start_time max_wait_time: current_url driver.current_url # 登录成功后通常会跳转回淘宝首页(www.taobao.com)或会员中心(my.taobao.com) if www.taobao.com in current_url and login not in current_url: login_success True print(检测到已跳转至淘宝首页登录成功) break # 另一种成功状态页面上的“我的淘宝”等登录后元素出现 try: driver.find_element(By.LINK_TEXT, 我的淘宝) login_success True print(检测到‘我的淘宝’元素登录成功) break except: pass time.sleep(3) # 每3秒检查一次 print(f等待中... 已等待{int(time.time() - start_time)}秒) if not login_success: raise TimeoutError(扫码登录等待超时请检查网络或手动重试。) # 登录成功后建议获取并保存cookies以备后续使用避免重复扫码 cookies driver.get_cookies() # 可以将cookies以json格式保存到文件 import json with open(taobao_cookies.json, w) as f: json.dump(cookies, f) print(登录成功Cookies已保存。) return driver3.3 登录环节的常见问题与排查技巧找不到登录按钮/元素定位失败这是最常见的问题。淘宝的页面结构会频繁变动。解决方案不要依赖固定的文本如“亲请登录”而是使用开发者工具F12仔细查看目标元素的id、class、>def search_product(driver, keyword, max_scroll5): 在淘宝搜索商品并模拟滚动加载更多结果。 :param driver: 已登录的浏览器驱动 :param keyword: 搜索关键词 :param max_scroll: 最大滚动加载次数 :return: 无停留在加载后的搜索结果页 print(f正在搜索商品: {keyword}) # 定位搜索框 try: search_input WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, q)) # 淘宝搜索框的ID通常是‘q’ ) search_input.clear() search_input.send_keys(keyword) print(关键词已输入。) except Exception as e: print(f定位搜索框失败: {e}) driver.save_screenshot(search_box_error.png) raise # 点击搜索按钮 try: search_button driver.find_element(By.CSS_SELECTOR, .btn-search) # 搜索按钮的CSS选择器 search_button.click() print(已点击搜索。) except: # 如果找不到按钮尝试用回车键 from selenium.webdriver.common.keys import Keys search_input.send_keys(Keys.ENTER) print(通过回车键执行搜索。) # 等待搜索结果页面加载完成 WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, .m-itemlist .items .item)) # 等待商品条目出现 ) print(搜索结果页加载完成。) # 模拟滚动以加载更多商品处理动态加载 print(开始模拟滚动加载更多商品...) last_height driver.execute_script(return document.body.scrollHeight) scroll_count 0 while scroll_count max_scroll: # 滚动到页面底部 driver.execute_script(window.scrollTo(0, document.body.scrollHeight);) # 等待新内容加载 time.sleep(2.5) # 等待时间很关键太短可能内容未加载太长效率低 new_height driver.execute_script(return document.body.scrollHeight) if new_height last_height: print(已滚动到底部或无新内容加载。) break last_height new_height scroll_count 1 print(f已完成第 {scroll_count} 次滚动当前页面高度: {new_height}) print(商品列表加载完毕。)4.2 解析列表页商品数据滚动加载完成后页面包含了大量商品卡片。我们需要解析这些卡片的HTML结构来提取信息。def parse_product_list(driver): 从当前搜索结果页解析商品列表信息。 :return: 商品信息字典列表 product_list [] # 淘宝商品卡片的CSS选择器可能会变这里是一个常见示例 items driver.find_elements(By.CSS_SELECTOR, .m-itemlist .items .item.J_MouserOnverReq) print(f共找到 {len(items)} 个商品卡片。) for index, item in enumerate(items): try: product_info {} # 1. 商品标题和链接 title_element item.find_element(By.CSS_SELECTOR, .title a) product_info[title] title_element.text.strip() product_info[link] title_element.get_attribute(href) # 从链接中提取商品ID import re match re.search(rid(\d), product_info[link]) product_info[product_id] match.group(1) if match else None # 2. 价格 try: price_element item.find_element(By.CSS_SELECTOR, .price strong) product_info[price] price_element.text.strip() except: product_info[price] N/A # 3. 销量 try: sales_element item.find_element(By.CSS_SELECTOR, .deal-cnt) product_info[sales] sales_element.text.strip() except: product_info[sales] N/A # 4. 店铺名 try: shop_element item.find_element(By.CSS_SELECTOR, .shopname) product_info[shop] shop_element.text.strip() except: product_info[shop] N/A # 5. 店铺所在地 try: location_element item.find_element(By.CSS_SELECTOR, .location) product_info[location] location_element.text.strip() except: product_info[location] N/A product_list.append(product_info) # print(f已解析商品: {product_info[title][:30]}...) except Exception as e: print(f解析第 {index1} 个商品时出错: {e}) # 可以继续解析下一个商品 continue print(f成功解析 {len(product_list)} 个商品信息。) return product_list实操心得淘宝的HTML结构是出了名的复杂且多变。上面使用的CSS选择器如.m-itemlist .items .item可能在未来失效。最可靠的方法是在浏览器中打开淘宝搜索结果页按F12打开开发者工具使用元素选择器CtrlShiftC点击一个商品卡片仔细分析其DOM结构找到当前稳定且能唯一定位商品容器的类名或属性。通常商品卡片会有一个包含>def navigate_to_product_detail(driver, product_link): 安全地导航到商品详情页处理可能的中间跳转页。 print(f正在访问商品详情页: {product_link}) driver.get(product_link) # 等待页面稳定可能是跳转后的最终页面 time.sleep(2) current_url driver.current_url # 检查是否成功到达详情页 if item.taobao.com in current_url or detail.tmall.com in current_url: print(f成功进入详情页: {current_url}) return True else: print(f可能仍在跳转页或错误页面当前URL: {current_url}) # 可以尝试查找并点击“继续访问”之类的按钮 try: continue_btn driver.find_element(By.LINK_TEXT, 继续访问) continue_btn.click() time.sleep(2) if item.taobao.com in driver.current_url or detail.tmall.com in driver.current_url: print(通过点击‘继续访问’进入详情页。) return True except: pass return False5.2 定位并爬取评论数据处理Ajax与翻页淘宝/天猫的评论是异步加载的需要找到评论区域的入口并模拟点击“下一页”来获取更多数据。def crawl_product_comments(driver, max_pages5): 爬取当前商品详情页的评论数据。 :param max_pages: 最多爬取的评论页数 :return: 评论字典列表 all_comments [] # 1. 尝试定位并切换到“评价”标签页 try: # 天猫和淘宝的评论标签选择器不同需要适配 # 常见选择器包含“评价”二字的标签 comment_tab WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, //div[contains(class, tab)]//a[contains(text(), 评价)])) ) # 滚动到该元素位置 driver.execute_script(arguments[0].scrollIntoView(true);, comment_tab) time.sleep(1) comment_tab.click() print(已切换到评价标签页。) time.sleep(3) # 等待评论内容加载 except Exception as e: print(f可能无需切换标签或标签定位失败: {e}) # 可能页面默认就在评价部分或者结构不同 # 直接尝试查找评论列表 # 2. 解析当前页的评论 page_num 1 while page_num max_pages: print(f正在爬取第 {page_num} 页评论...) # 等待评论列表容器加载 try: WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, .rate-grid .rate-list .rate-item)) ) except: print(未找到评论列表可能该商品无评论或页面结构有变。) break # 找到所有评论条目 comment_items driver.find_elements(By.CSS_SELECTOR, .rate-grid .rate-list .rate-item) print(f第 {page_num} 页找到 {len(comment_items)} 条评论。) if len(comment_items) 0: break for item in comment_items: try: comment_data {} # 买家昵称可能脱敏 try: comment_data[user] item.find_element(By.CSS_SELECTOR, .user-info .user-nick).text.strip() except: comment_data[user] 匿名用户 # 评论内容 try: comment_data[content] item.find_element(By.CSS_SELECTOR, .rate-content .rate-full-text).text.strip() except: # 有些评论可能没有展开全文 try: comment_data[content] item.find_element(By.CSS_SELECTOR, .rate-content .rate-sku).text.strip() except: comment_data[content] N/A # 评论时间 try: comment_data[time] item.find_element(By.CSS_SELECTOR, .rate-time).text.strip() except: comment_data[time] N/A # 商品规格如颜色、尺寸 try: comment_data[sku] item.find_element(By.CSS_SELECTOR, .rate-sku).text.strip() except: comment_data[sku] N/A # 追加评论如果有 try: append_comment item.find_element(By.CSS_SELECTOR, .rate-append) comment_data[append_content] append_comment.text.strip() except: comment_data[append_content] all_comments.append(comment_data) except Exception as e: print(f解析单条评论时出错: {e}) continue # 3. 尝试翻到下一页 page_num 1 if page_num max_pages: break try: # 查找“下一页”按钮注意可能被禁用或不存在 next_page_btn driver.find_element(By.CSS_SELECTOR, .rate-paginator a.next:not(.disabled)) # 滚动到下一页按钮 driver.execute_script(arguments[0].scrollIntoView(true);, next_page_btn) time.sleep(1) next_page_btn.click() print(点击下一页按钮。) time.sleep(3) # 等待新一页评论加载 except Exception as e: print(f无法找到或点击下一页按钮可能已是最后一页。错误: {e}) break print(f评论爬取结束共获取 {len(all_comments)} 条评论。) return all_comments5.3 评论数据爬取的高级技巧与反反爬随机延迟与人性化操作在翻页和点击操作之间加入随机等待时间如time.sleep(random.uniform(1.5, 3.5))模拟人类阅读和操作的不确定性避免请求过于规律而被识别。处理“点击查看更多评价”有些商品默认只显示部分评价需要点击一个链接才能展开全部。在爬取前可以检查是否存在这样的元素并点击它。try: view_more driver.find_element(By.LINK_TEXT, 点击查看更多评价) view_more.click() time.sleep(2) except: pass应对“评价暂时无法显示”这是淘宝常见的反爬手段。如果遇到可能意味着你的请求被识别为爬虫。应对策略立即停止操作检查你的浏览器指纹伪装是否完好更换IP地址如果有条件或者直接使用该账号在真实浏览器中手动浏览一段时间降低风险后再尝试。数据清洗爬取到的评论可能包含大量无关字符如表情符号、空格、换行、广告或默认好评。在存储前需要进行基本的清洗例如使用正则表达式移除特殊字符过滤掉内容过短如少于5个字的评论。6. 数据存储、调度与伦理边界6.1 数据存储方案选择爬取到的数据需要持久化。对于中小规模爬虫推荐以下方案CSV文件轻量、易读、兼容性好。使用Python内置的csv模块或pandas的to_csv方法。适合存储结构化的列表页商品信息和评论。import pandas as pd # 假设 product_list 和 all_comments 是上面函数返回的列表 df_products pd.DataFrame(product_list) df_comments pd.DataFrame(all_comments) df_products.to_csv(ftaobao_products_{keyword}.csv, indexFalse, encodingutf_8_sig) # 解决中文乱码 df_comments.to_csv(ftaobao_comments_{product_id}.csv, indexFalse, encodingutf_8_sig)SQLite数据库如果数据之间存在关系如一个商品对应多条评论或者需要频繁查询SQLite是更好的选择。它无需安装服务器单个文件即可管理。JSON文件适合存储嵌套结构复杂的数据或者用于保存中间状态如cookies。6.2 脚本调度与稳定性优化一个完整的爬虫脚本应该具备一定的健壮性能够处理异常并从中恢复。异常捕获与重试在网络请求、元素查找等可能失败的环节使用try...except并加入重试逻辑。from tenacity import retry, stop_after_attempt, wait_fixed retry(stopstop_after_attempt(3), waitwait_fixed(2)) def safe_find_element(driver, by, value): return WebDriverWait(driver, 10).until(EC.presence_of_element_located((by, value)))使用会话Session保存状态登录成功后保存cookies到文件。下次运行时可以先尝试加载cookies并注入到浏览器如果仍然保持登录态则无需再次扫码极大提升效率。def load_cookies_and_refresh(driver, cookie_filetaobao_cookies.json): try: with open(cookie_file, r) as f: cookies json.load(f) driver.get(https://www.taobao.com) # 先访问域名 for cookie in cookies: # 有些cookie字段如‘expiry’可能是浮点数需要处理 if expiry in cookie: cookie[expiry] int(cookie[expiry]) driver.add_cookie(cookie) driver.refresh() # 刷新页面使cookies生效 time.sleep(3) # 检查是否登录成功 if driver.find_elements(By.LINK_TEXT, 我的淘宝): print(通过Cookies登录成功) return True except: pass return False设置合理的爬取间隔在循环爬取多个商品时务必在请求间加入随机延时遵守robots.txt虽然淘宝通常禁止爬虫这是对目标网站最基本的尊重也能保护你的IP和账号。6.3 法律与伦理边界这是最重要的一环。爬取公开数据虽常见但必须明确边界遵守robots.txt访问https://www.taobao.com/robots.txt查看淘宝对爬虫的限制。尽管技术上可以绕过但违反它可能带来法律风险。限制爬取速度与频率不要对服务器造成DoS攻击式的压力。将请求频率控制在人类浏览的水平。尊重数据版权与用户隐私爬取的数据仅用于个人学习、研究或合法的市场分析。绝对禁止用于商业售卖、骚扰用户、欺诈等非法用途。评论数据中可能包含用户昵称公开使用时应做脱敏处理。账号安全用于登录的淘宝账号是你个人的。频繁、异常的自动化操作可能导致账号被限制登录或封禁。请使用不重要的“小号”进行测试并承担相应风险。整个项目从环境搭建到数据落地的闭环就完成了。核心思想是“模拟”而非“攻击”通过理解网站的正常交互流程让程序以尽可能接近真人的方式运行从而在满足需求的同时将风险和对目标网站的影响降到最低。在实际操作中耐心调试元素选择器、灵活应对页面变化、严格遵守爬虫伦理是项目成功的关键。