# 代码说明:
'''
代码功能: 基于ChromeDriver爬取taobao(淘宝)平台商品列表数据
输入参数: KEYWORLD --> 搜索商品“关键词”;
输出文件:爬取商品列表数据
'Num' :序号
'title' :商品标题
'Price' :商品价格
'Deal' :商品销量
'Location' :地理位置
'Shop' :商品
'IsPostFree' :是否包邮
'Title_URL' :商品详细页链接
'Shop_URL' :商铺链接
'Img_URL' :图片链接
'''
# 声明第三方库/头文件
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
import time
import openpyxl as op #导入Excel读写库
# import pyperclip
import win32clipboard
from io import BytesIO
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import sys
# 全局变量
count = 1 # 写入Excel商品计数
# 启动ChromeDriver服务
options = webdriver.ChromeOptions()
# 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
options.add_experimental_option("excludeSwitches", ['enable-automation'])
# 把chrome设为selenium驱动的浏览器代理;
driver = webdriver.Chrome(options=options)
# 反爬机制
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",
{"source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"""})
driver.get('https://www.taobao.com')
# 窗口最大化
driver.maximize_window()
# wait是Selenium中的一个等待类,用于在特定条件满足之前等待一定的时间(这里是15秒)。
# 如果一直到等待时间都没满足则会捕获TimeoutException异常
wait = WebDriverWait(driver,10)
# 打开页面后会强制停止10秒,请在此时手动扫码登陆
# 在 Windows 系统中,可以使用 pywin32 将图像文件复制到剪贴板,pyperclip 主要用于复制文本内容
def copy_image_to_clipboard(image_path):
# 打开图像文件
image = Image.open(image_path)
# 将图像转换为 BMP 格式
output = BytesIO()
image.convert('RGB').save(output, 'BMP')
data = output.getvalue()[14:] # BMP 文件头的前 14 字节需要跳过
output.close()
# 打开剪贴板
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data) # CF_DIB 是 Windows 用于图像的格式
win32clipboard.CloseClipboard()
# 根据图片,搜索
def search_goods(img_file):
try:
# 找到“搜同款”按钮
print("准备开始以图搜物")
search_image = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".search-suggest-image-search-out-icon")))
search_image.click()
# 复制图片到剪贴板
copy_image_to_clipboard(img_file)
time.sleep(3)
image = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".image-search-success-img-wrapper")))
# 模拟 Ctrl+V 粘贴操作
actions = ActionChains(driver)
actions.key_down(Keys.CONTROL,image).send_keys('v').key_up(Keys.CONTROL,image).perform()
# 找到“搜索”按钮
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#image-search-upload-button')))
# 点击“搜索”按键
submit.click()
# 搜索商品后会再强制停止2秒,如有滑块请手动操作
time.sleep(2)
print("搜索完成!")
except Exception as exc:
print("search_goods函数错误!")
# 获取每一页的商品信息;
def get_goods():
try:
# 声明全局变量count
global count
# if input('确认界面加载完毕,输入数字“1”开始爬取-->') == 1:
# pass
# 因为跳转新页面了,需要切换到新页面的窗口或标签页,然后才能获取新页面的 page_source
# 获取所有窗口句柄
time.sleep(10)
window_handles = driver.window_handles
# 切换到新窗口(假设新窗口是最后一个打开的)
driver.switch_to.window(window_handles[-1])
# 获取html网页
print("开始获取商品信息")
html = driver.page_source
doc = pq(html)
# 打开一个文件用于写入
with open('output.txt', 'w', encoding='utf-8') as file:
# 将 print 的输出重定向到文件
sys.stdout = file
# 所有 print 的内容都会写入文件
print(doc)
# 恢复标准输出
sys.stdout = sys.__stdout__
# 提取所有商品的共同父元素的类选择器
items = doc('div.content--CUnfXXxv > div > a').items()
for item in items:
# 定位商品标题
title = item.find('.title--qJ7Xg_90 span').text()
# 定位价格
price_int = item.find('.priceInt--yqqZMJ5a').text()
price_float = item.find('.priceFloat--XpixvyQ1').text()
if price_int and price_float:
price = float(f"{price_int}{price_float}")
else:
price = 0.0
# 定位交易量
deal = item.find('.realSales--XZJiepmt').text()
# 定位所在地信息
location = item.find('.procity--wlcT2xH9 span').text()
# 定位店名
shop = item.find('.shopNameText--DmtlsDKm').text()
# 定位包邮的位置
postText = item.find('.subIconWrapper--Vl8zAdQn').text()
postText = "包邮" if "包邮" in postText else "/"
# 定位商品url
t_url = item.find('.doubleCardWrapperAdapt--mEcC7olq')
t_url = t_url.attr('href')
# t_url = item.attr('a.doubleCardWrapperAdapt--mEcC7olq href')
# 定位店名url
shop_url = item.find('.TextAndPic--grkZAtsC a')
shop_url = shop_url.attr('href')
# 定位商品图片url
img = item.find('.mainPicAdaptWrapper--V_ayd2hD img')
img_url = img.attr('src')
# 定位风格
style_list = item('div.abstractWrapper--whLX5va5 > div').items()
style = []
for s in style_list:
s_span = s('div.descBox--RunOO4S3 > span').text()
if s_span != '':
style.append(s_span)
# 构建商品信息字典
product = {
'Num': count-1,
'title': title,
'price': price,
'deal': deal,
'location': location,
'shop': shop,
'isPostFree': postText,
'url': t_url,
'shop_url': shop_url,
'img_url': img_url
}
print(product)
# 商品信息写入Excel表格中
wb.cell(row=count, column=2, value=count-1) # 序号
wb.cell(row=count, column=3, value=title) # 标题
wb.cell(row=count, column=4, value=price) # 价格
wb.cell(row=count, column=5, value=deal) # 付款人数
wb.cell(row=count, column=6, value=location) # 地理位置
wb.cell(row=count, column=7, value=shop) # 店铺名称
wb.cell(row=count, column=8, value=postText) # 是否包邮
wb.cell(row=count, column=9, value=t_url) # 商品链接
wb.cell(row=count, column=10, value=shop_url) # 商铺链接
wb.cell(row=count, column=11, value=img_url) # 图片链接
for i in range(0,len(style)):
wb.cell(row=count, column=12+i, value=style[i]) # 风格1~3
count += 1 # 下一行
except Exception:
print("get_goods函数错误!")
# 爬虫main函数
def Crawer_main():
try:
# 搜索KEYWORD
search_goods('4.png')
# 爬取商品信息
get_goods()
except Exception as exc:
print("Crawer_main函数错误!")
if __name__ == '__main__':
# 建立Excel表格
try:
ws = op.Workbook() # 创建Workbook
wb = ws.create_sheet(index=0) # 创建worsheet
# Excel第一行:表头
title_list = ['Page', 'Num', 'title', 'Price', 'Deal', 'Location', 'Shop', 'IsPostFree', 'Title_URL',
'Shop_URL', 'Img_URL', 'Style_1', 'Style_2', 'Style_3']
for i in range(0, len(title_list)):
wb.cell(row=count, column=i + 1, value=title_list[i])
count += 1 # 从第二行开始写爬取数据
print("Excel建立!")
except Exception as exc:
print("Excel建立失败!")
# 开始爬取数据
Crawer_main()
# 保存Excel表格
data = time.strftime('%Y%m%d-%H%M', time.localtime(time.time()))
Filename = "No.{}_FromTB.xlsx".format(data)
ws.save(filename = Filename)
print(Filename + "存储成功~")