selenium跳过webdriver检测并爬取淘宝我已购买的宝贝数据

本文介绍了一种使用Selenium自动化浏览器工具跳过webdriver检测的方法,实现对天猫商品数据的爬取。文章详细展示了如何利用Selenium模拟真实用户行为,包括登录流程、浏览商品列表及获取商品详情等,特别强调了防止被识别为机器人的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

上一个博文已经讲述了如何使用selenium跳过webdriver检测并爬取天猫商品数据,所以在此不再详细讲,有需要思路的可以查看另外一篇博文。

源代码


    # -*- coding: utf-8 -*-

from selenium import webdriver
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
from time import sleep
import random


#定义一个taobao类
class taobao_infos:

    #对象初始化
    def __init__(self):
        url = 'https://login.taobao.com/member/login.jhtml'
        self.url = url

        options = webdriver.ChromeOptions()
        options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2}) # 不加载图片,加快访问速度
        options.add_experimental_option('excludeSwitches', ['enable-automation']) # 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium
        self.browser = webdriver.Chrome(executable_path=chromedriver_path, options=options)

        self.wait = WebDriverWait(self.browser, 10) #超时时长为10s


    #登录淘宝
    def login(self):

        # 打开网页
        self.browser.get(self.url)

        # 自适应等待,点击密码登录选项
        self.browser.implicitly_wait(30) #智能等待,直到网页加载完毕,最长等待时间为30s
        self.browser.find_element_by_xpath('//*[@class="forget-pwd J_Quick2Static"]').click()

        # 自适应等待,点击微博登录宣传
        self.browser.implicitly_wait(30)
        self.browser.find_element_by_xpath('//*[@class="weibo-login"]').click()

        # 自适应等待,输入微博账号
        self.browser.implicitly_wait(30)
        self.browser.find_element_by_name('username').send_keys(weibo_username)

        # 自适应等待,输入微博密码
        self.browser.implicitly_wait(30)
        self.browser.find_element_by_name('password').send_keys(weibo_password)

        # 自适应等待,点击确认登录按钮
        self.browser.implicitly_wait(30)
        self.browser.find_element_by_xpath('//*[@class="btn_tip"]/a/span').click()

        # 直到获取到淘宝会员昵称才能确定是登录成功
        taobao_name = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.site-nav-bd > ul.site-nav-bd-l > li#J_SiteNavLogin > div.site-nav-menu-hd > div.site-nav-user > a.site-nav-login-info-nick ')))
        # 输出淘宝昵称
        print(taobao_name.text)


    # 模拟向下滑动浏览
    def swipe_down(self,second):
        for i in range(int(second/0.1)):
            #根据i的值,模拟上下滑动
            if(i%2==0):
                js = "var q=document.documentElement.scrollTop=" + str(300+400*i)
            else:
                js = "var q=document.documentElement.scrollTop=" + str(200 * i)
            self.browser.execute_script(js)
            sleep(0.1)

        js = "var q=document.documentElement.scrollTop=100000"
        self.browser.execute_script(js)
        sleep(0.1)


    # 爬取淘宝 我已买到的宝贝商品数据
    def crawl_good_buy_data(self):

        # 对我已买到的宝贝商品数据进行爬虫
        self.browser.get("https://buyertrade.taobao.com/trade/itemlist/list_bought_items.htm")

        # 遍历所有页数
        for page in range(1,1000):

            # 等待该页面全部已买到的宝贝商品数据加载完毕
            good_total = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#tp-bought-root > div.js-order-container')))

            # 获取本页面源代码
            html = self.browser.page_source

            # pq模块解析网页源代码
            doc = pq(html)

            # # 存储该页已经买到的宝贝数据
            good_items = doc('#tp-bought-root .js-order-container').items()

            # 遍历该页的所有宝贝
            for item in good_items:
                good_time_and_id = item.find('.bought-wrapper-mod__head-info-cell___29cDO').text().replace('\n',"").replace('\r',"")
                good_merchant = item.find('.seller-mod__container___1w0Cx').text().replace('\n',"").replace('\r',"")
                good_name = item.find('.sol-mod__no-br___1PwLO').text().replace('\n', "").replace('\r', "")
                # 只列出商品购买时间、订单号、商家名称、商品名称
                # 其余的请自己实践获取
                print(good_time_and_id, good_merchant, good_name)

            print('\n\n')

            # 大部分人被检测为机器人就是因为进一步模拟人工操作
            # 模拟人工向下浏览商品,即进行模拟下滑操作,防止被识别出是机器人
            # 随机滑动延时时间
            swipe_time = random.randint(1, 3)
            self.swipe_down(swipe_time)


            # 等待下一页按钮 出现
            good_total = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.pagination-next')))
            # 点击下一页按钮
            good_total.click()
            sleep(2)



if __name__ == "__main__":

    # 使用之前请先查看当前目录下的使用说明文件README.MD
    # 使用之前请先查看当前目录下的使用说明文件README.MD
    # 使用之前请先查看当前目录下的使用说明文件README.MD

    chromedriver_path = "/Users/bird/Desktop/chromedriver.exe" #改成你的chromedriver的完整路径地址
    weibo_username = "改成你的微博账号" #改成你的微博账号
    weibo_password = "改成你的微博密码" #改成你的微博密码

    a = taobao_infos()
    a.login() #登录
    a.crawl_good_buy_data() #爬取淘宝 我已买到的宝贝商品数据
    
复制代码

使用教程

  1. 点击这里下载下载chrome浏览器
  2. 查看chrome浏览器的版本号,点击这里下载对应版本号的chromedriver驱动
  3. pip安装下列包
    • pip install selenium
  4. 点击这里登录微博,并通过微博绑定淘宝账号密码
  5. 在main中填写chromedriver的绝对路径
  6. 在main中填写微博账号密码

	#改成你的chromedriver的完整路径地址
    chromedriver_path = "/Users/bird/Desktop/chromedriver.exe" 
    #改成你的微博账号
    weibo_username = "改成你的微博账号"
    #改成你的微博密码
    weibo_password = "改成你的微博密码"
    
复制代码

演示图片

爬虫过程图片查看不了点击这里 爬虫结果图片查看不了点击这里

其他爬虫源代码

所有关于爬虫的项目都放在github了,有需要的可以去GitHub仓库

项目持续更新,欢迎您star本项目

<think>我们使用Selenium来模拟浏览器获取考试宝的题目页面,因为考试宝可能使用了JavaScript动态加载内容,且有字体加密(TTF字体)。我们的解决方案包括以下步骤: 1. 使用Selenium获取页面源代码(包含加密字体的HTML) 2. 从页面中提取字体文件的URL(可能是.ttf或.woff格式) 3. 下载字体文件使用`fontTools`解析 4. 构建加密字符到实际字符的映射关系 5. 替换页面中的加密字符为实际字符 6. 解析题目提取内容 注意:考试宝的字体加密每次可能不同,但通常数字的映射关系是固定的(即字形结构不变,但编码会变)。因此,我们可以通过比较字形来识别数字(0-9)或者字母。 但是,由于考试宝的字体加密可能使用自定义的映射,我们需要动态解析字体文件,建立当前字体文件中字符编码与真实字符的对应关系。 这里我们采用两种方法: 方法1:通过字体文件中字符的名称(如'uniE050')来推断真实字符(因为名称中的十六进制部分减去一个基准值后可能对应一个数字) 方法2:通过比较字形轮廓的坐标与基准字形坐标的相似度(如果方法1失效,则用此方法) 由于考试宝的字体加密通常用于数字,我们重点关注数字0-9。 下面我们使用Selenium和fontTools实现爬虫: 步骤: 1. 配置Selenium WebDriver(这里以Chrome为例) 2. 访问目标URL 3. 获取页面源码 4. 从源码中提取字体文件URL(通常是ttf或woff) 5. 下载字体文件解析 6. 构建映射关系(这里优先使用方法1,如果方法1不奏效则使用方法2) 7. 替换页面中的加密字符 8. 使用BeautifulSoup解析题目 注意:考试宝的题目可能包含在动态加载的元素中,确保我们获取到题目内容后再进行解析。 代码实现如下:</think># 使用Selenium WebDriver爬取考试宝题目处理TTF字体加密 下面我将提供一个完整的解决方案,使用Selenium WebDriver爬取考试宝题目处理TTF字体加密问题。这个方案结合了Selenium的动态页面处理能力和字体解析技术,能够有效应对考试宝的反爬措施。 ```python import re import time import io import requests from fontTools.ttLib import TTFont from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from bs4 import BeautifulSoup import matplotlib.pyplot as plt from PIL import Image, ImageDraw, ImageFont import numpy as np from sklearn.neighbors import NearestNeighbors # 配置Selenium WebDriver def setup_driver(): chrome_options = Options() chrome_options.add_argument("--headless") # 无头模式 chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") # 防止WebDriver检测 chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument('--disable-blink-features=AutomationControlled') service = Service(executable_path='chromedriver') # 替换为你的chromedriver路径 driver = webdriver.Chrome(service=service, options=chrome_options) # 绕过WebDriver检测 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """ }) return driver # 获取页面内容 def get_page(driver, url): driver.get(url) # 等待页面加载完成 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".question-item")) ) # 等待可能的字体加载 time.sleep(2) return driver.page_source # 提取字体文件URL def extract_font_url(html): # 匹配CSS中的字体URL pattern = r"src:\s*url\('(.*?\.ttf)'\)\s*format\('truetype'\)" match = re.search(pattern, html) if match: return match.group(1) # 匹配HTML中的字体链接 soup = BeautifulSoup(html, 'html.parser') link_tags = soup.find_all('link', {'rel': 'stylesheet'}) for tag in link_tags: if tag.get('href') and 'font' in tag.get('href'): return tag.get('href') return None # 下载字体文件 def download_font(font_url): response = requests.get(font_url) return io.BytesIO(response.content) # 基础字体映射方法 def basic_font_mapping(font): cmap = font.getBestCmap() mapping = {} # 常见考试宝字体映射模式 for code, name in cmap.items(): # 模式1: uniE050 -> 0 if name.startswith('uni'): hex_value = name[3:] try: num = int(hex_value, 16) - 0xE000 if 0 <= num <= 9: mapping[chr(code)] = str(num) except: pass # 模式2: glyph00001 -> 1 if name.startswith('glyph'): try: num = int(name[5:]) if 0 <= num <= 9: mapping[chr(code)] = str(num) except: pass return mapping # 高级字形匹配方法 def advanced_font_mapping(font): # 创建基础数字的参考图像 base_font = ImageFont.truetype("arial.ttf", 40) base_images = {} for num in range(10): img = Image.new('L', (50, 50), 255) draw = ImageDraw.Draw(img) draw.text((10, 5), str(num), font=base_font, fill=0) base_images[str(num)] = np.array(img) # 获取字体中的字形 glyph_order = font.getGlyphOrder()[2:] # 跳过前两个系统字形 mapping = {} for glyph_name in glyph_order: # 创建当前字形的图像 glyph_img = Image.new('L', (50, 50), 255) draw = ImageDraw.Draw(glyph_img) # 获取字形的Unicode值 unicode_val = None for code, name in font.getBestCmap().items(): if name == glyph_name: unicode_val = chr(code) break if not unicode_val: continue # 绘制当前字形 try: # 使用临时字体绘制 temp_font = ImageFont.truetype(io.BytesIO(font.reader.file.read()), 40) draw.text((10, 5), unicode_val, font=temp_font, fill=0) except: continue glyph_array = np.array(glyph_img) # 与基础数字比较相似度 best_match = None min_diff = float('inf') for num, base_img in base_images.items(): diff = np.sum(np.abs(glyph_array - base_img)) if diff < min_diff: min_diff = diff best_match = num if best_match: mapping[unicode_val] = best_match return mapping # 解析字体文件 def parse_font(font_data): font = TTFont(font_data) # 尝试基础映射方法 mapping = basic_font_mapping(font) # 如果基础映射不完整,尝试高级方法 if len(mapping) < 10: advanced_mapping = advanced_font_mapping(font) mapping.update(advanced_mapping) return mapping # 替换加密文本 def decrypt_text(text, mapping): for char, num in mapping.items(): text = text.replace(char, num) return text # 提取题目内容 def extract_questions(html, mapping): soup = BeautifulSoup(html, 'html.parser') questions = [] # 解密整个HTML decrypted_html = decrypt_text(str(soup), mapping) soup = BeautifulSoup(decrypted_html, 'html.parser') # 定位题目元素 - 根据考试宝实际结构调整 question_items = soup.select('.question-item') for item in question_items: try: # 提取题目文本 title_elem = item.select_one('.title, .question-title, .q-title') title = title_elem.get_text(strip=True) if title_elem else "未找到题目" # 提取选项 options = [] option_elems = item.select('.option, .question-option, .option-item') for opt in option_elems: options.append(opt.get_text(strip=True)) # 提取答案 answer_elem = item.select_one('.answer, .question-answer, .correct-answer') answer = answer_elem.get_text(strip=True) if answer_elem else "未找到答案" # 提取解析(如果有) analysis_elem = item.select_one('.analysis, .question-analysis') analysis = analysis_elem.get_text(strip=True) if analysis_elem else "" questions.append({ 'title': title, 'options': options, 'answer': answer, 'analysis': analysis }) except Exception as e: print(f"提取题目时出错: {e}") return questions # 主函数 def main(): # 初始化WebDriver driver = setup_driver() try: # 考试宝题目页面URL - 替换为实际URL url = "https://www.zaixiankaoshi.com/exam/some-exam-id" # 获取页面内容 html = get_page(driver, url) # 提取字体URL font_url = extract_font_url(html) if not font_url: print("未检测到字体文件") return # 下载解析字体 font_data = download_font(font_url) mapping = parse_font(font_data) print(f"字体映射关系: {mapping}") # 提取解密题目 questions = extract_questions(html, mapping) # 输出结果 print(f"\n爬取到 {len(questions)} 道题目:") for i, q in enumerate(questions, 1): print(f"\n题目 {i}: {q['title']}") for j, opt in enumerate(q['options']): print(f" {chr(65+j)}. {opt}") print(f"答案: {q['answer']}") if q['analysis']: print(f"解析: {q['analysis']}") finally: # 关闭浏览器 driver.quit() if __name__ == "__main__": main() ``` ## 解决方案关键技术解析 ### 1. Selenium WebDriver配置 ```python def setup_driver(): chrome_options = Options() chrome_options.add_argument("--headless") # 无头模式 # 防止WebDriver检测 chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) # 绕过WebDriver检测 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """ }) ``` 这段代码配置了Selenium WebDriver,特别添加了绕过WebDriver检测的措施,这对于考试宝等具有反爬机制的网站至关重要[^1]。 ### 2. 字体加密处理核心技术 考试宝使用TTF字体加密时,我们采用两种映射方法: **方法1:基础映射(基于命名规则)** ```python def basic_font_mapping(font): for code, name in cmap.items(): # 模式1: uniE050 -> 0 if name.startswith('uni'): hex_value = name[3:] num = int(hex_value, 16) - 0xE000 if 0 <= num <= 9: mapping[chr(code)] = str(num) ``` **方法2:高级字形匹配(基于图像相似度)** ```python def advanced_font_mapping(font): # 创建基础数字图像 base_images = {} for num in range(10): img = Image.new('L', (50, 50), 255) draw = ImageDraw.Draw(img) draw.text((10, 5), str(num), font=base_font, fill=0) base_images[str(num)] = np.array(img) # 比较字形相似度 for glyph_name in glyph_order: # ... glyph_array = np.array(glyph_img) for num, base_img in base_images.items(): diff = np.sum(np.abs(glyph_array - base_img)) if diff < min_diff: best_match = num ``` 这种方法通过比较加密字形与标准数字的图像差异,找到最匹配的数字,有效应对字体动态变化[^2]。 ### 3. 动态页面处理 ```python def get_page(driver, url): driver.get(url) # 等待题目加载 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".question-item")) ) # 等待字体加载 time.sleep(2) return driver.page_source ``` 使用显式等待确保题目内容完全加载,避免因动态内容导致的数据缺失问题[^4]。 ## 实际应用注意事项 1. **字体映射更新** - 考试宝可能定期更新字体映射规则,需定期验证映射准确性 - 建议保存历史字体文件建立映射库 2. **反爬升级应对** - IP轮换:使用代理池防止IP被封 ```python chrome_options.add_argument('--proxy-server=http://your-proxy-ip:port') ``` - 请求频率控制:添加随机延迟 ```python import random time.sleep(random.uniform(1, 3)) ``` 3. **验证码处理** - 使用第三方打码平台处理验证码 - 人工干预机制:遇到验证码时暂停等待人工输入 4. **性能优化** - 复用WebDriver实例爬取多个页面 - 使用浏览器缓存减少资源加载 ```python chrome_options.add_argument("--disk-cache-dir=/path/to/cache") chrome_options.add_argument("--disk-cache-size=104857600") # 100MB缓存 ``` ## 相关扩展问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值