影刀RPA 网页卡片列表采集:流式布局提取
作者:林焱
什么情况用什么
现在很多网站的列表页不是传统表格,而是卡片式布局——商品卡片、新闻列表、视频列表——每个卡片是一个独立的div块,包含标题、图片、价格、链接等信息。这种布局用传统的表格提取方法取不到数据,需要逐个卡片解析。
适用场景:电商商品列表采集、新闻资讯列表采集、视频网站内容列表、社交媒体帖子列表。
怎么做
卡片列表采集基本流程
1. 【打开网页】→ 打开商品列表页 2. 【等待元素出现】→ 等待卡片容器加载 3. 【执行Python代码】→ 解析所有卡片 4. 【翻页】→ 点击下一页或滚动加载 5. [video(video-9YBE4VmK-1784736622564)(type-csdn)(url-https://live.csdn.net/v/embed/526818)(image-https://v-blog.csdnimg.cn/asset/582d14c3bd0451c5399cd990b56e2a0d/cover/Cover0.jpg)(title-拼多多店群自动化报活动上架!)] 6. 循环2-4直到采集完解析卡片数据
frombs4importBeautifulSoupimportrequestsdefscrape_card_list(url):"""采集卡片式列表"""headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}response=requests.get(url,headers=headers,timeout=10)soup=BeautifulSoup(response.text,'html.parser')# 找到所有卡片(需要根据实际网站调整选择器)cards=soup.select('.product-card')# 或 .item / .card / [data-id]results=[]forcardincards:item={}# 标题title_el=card.select_one('.title')# 或 h3 / .nameitem['标题']=title_el.get_text(strip=True)iftitle_elelse''# 价格price_el=card.select_one('.price')# 或 .cost / .amountitem['价格']=price_el.get_text(strip=True)ifprice_elelse''# 链接link_el=card.select_one('a')item['链接']=link_el.get('href','')iflink_elelse''# 图片img_el=card.select_one('img')item['图片']=img_el.get('src','')orimg_el.get('data-src','')ifimg_elelse''# 评分rating_el=card.select_one('.rating')item['评分']=rating_el.get_text(strip=True)ifrating_elelse''results.append(item)returnresults# 使用data=scrape_card_list("https://example.com/products")在影刀RPA中用可视化指令采集
1. 【打开网页】→ 商品列表URL 2. 【等待元素出现】→ 选择器 .product-card 3. 【提取相似元素数据】→ 配置每个字段的子选择器 - 标题:.product-card .title - 价格:.product-card .price - 链接:.product-card a → 属性href - 图片:.product-card img → 属性src 4. 【点击元素】→ 下一页按钮 5. 【循环】→ 直到没有下一页滚动加载(流式布局)
很多卡片列表不用翻页,而是滚动到底部自动加载更多:
importtimedefscrape_infinite_scroll(url,max_scrolls=20):"""采集无限滚动列表(需配合影刀浏览器)"""all_items=[]forscroll_countinrange(max_scrolls):# 在影刀中用【执行JavaScript代码】滚动# window.scrollTo(0, document.body.scrollHeight)# 等待新内容加载time.sleep(2)# 获取当前页面所有卡片# 在影刀中用【获取网页源代码】或【提取相似元素数据】current_cards=get_current_cards()# 需要实现# 检查是否有新数据iflen(current_cards)==len(all_items):print(f"第{scroll_count+1}次滚动无新数据,停止")breakall_items=current_cardsprint(f"第{scroll_count+1}次滚动,共{len(all_items)}条")returnall_items在影刀RPA中用JavaScript节点滚动:
// 影刀【执行JavaScript代码】节点window.scrollTo(0,document.body.scrollHeight);多字段卡片采集
defscrape_product_cards(html):"""采集商品卡片的多字段信息"""soup=BeautifulSoup(html,'html.parser')cards=soup.select('[class*="product"]')results=[]forcardincards:item={}# 多层嵌套选择item['商品名']=safe_extract(card,'.title, .name, h3')item['价格']=clean_price(safe_extract(card,'.price, .cost'))item['原价']=clean_price(safe_extract(card,'.original-price, .old-price'))item['销量']=safe_extract(card,'.sales, .sold')item['店铺']=safe_extract(card,'.shop-name, .store')# 标签(可能有多个)tags=card.select('.tag, .label, .badge')item['标签']='|'.join([t.get_text(strip=True)fortintags])# 链接(处理相对路径)link=card.select_one('a')iflink:href=link.get('href','')ifhref.startswith('//'):href='https:'+hrefelifhref.startswith('/'):href='https://example.com'+href item['链接']=href results.append(item)returnresultsdefsafe_extract(parent,selector_str):"""安全提取文本"""el=parent.select_one(selector_str)returnel.get_text(strip=True)ifelelse''defclean_price(text):"""清理价格文本"""importreifnottext:return''# 去掉¥符号和逗号text=re.sub(r'[¥¥,,]','',text)returntext.strip()有什么坑
坑1:卡片选择器不稳定
网站改版后class名变了,选择器失效:
# 问题:固定class名容易失效cards=soup.select('.product-card-item-2024')# 解决:用多个选择器做后备cards=soup.select('.product-card, .item-card, [data-product-id], .goods-item')# 或者用更稳定的属性cards=soup.select('[data-sku]')# 用data属性更稳定坑2:图片懒加载导致src为空
TEMU店群矩阵自动化运营核价报活动
# 问题:img的src是占位图,真实图片在data-src里img_el=card.select_one('img')src=img_el.get('src')# 拿到的是loading.gif# 解决:优先取data-srcsrc=img_el.get('data-src')orimg_el.get('data-original')orimg_el.get('src','')# 或者在影刀中先滚动到图片位置触发加载# 用【滚动到元素】指令坑3:卡片数量和实际不符
页面显示20个卡片,但只提取到15个——有些卡片是广告或推荐位,结构不同:
# 解决:加验证条件,只提取有效卡片forcardincards:# 必须有标题和价格才算有效商品卡片title=safe_extract(card,'.title')price=safe_extract(card,'.price')ifnottitleornotprice:continue# 跳过广告卡片item={'标题':title,'价格':price}results.append(item)坑4:列表数据重复
滚动加载时新数据追加到页面,但每次都重新提取所有卡片导致重复:
# 解决:用唯一标识去重seen_ids=set()results=[]forcardincards:# 用商品ID去重card_id=card.get('data-id')orcard.get('data-sku')ifcard_idandcard_idinseen_ids:continueifcard_id:seen_ids.add(card_id)item=parse_card(card)results.append(item)坑5:异步加载内容缺失
卡片的某些字段(如销量、评价数)是异步加载的,首次请求时还没有:
# 解决1:用影刀浏览器等待元素加载# 【等待元素出现】→ 销量选择器 → 超时5秒# 解决2:找到AJAX接口直接请求# F12 → Network → 找到返回销量数据的APIsales_api=f"https://example.com/api/product/{product_id}/stats"sales_response=requests.get(sales_api,headers=headers)sales_data=sales_response.json()item['销量']=sales_data.get('sold_count','')