ScrapeCenter爬虫练习

内容案例来自:https://scrape.center/
本人小白菜,仅供参考哦~

ssr1 & ssr2

案例ssr1:电影数据网站,无反爬,数据通过服务端渲染,适合基本爬虫练习。
案例ssr2:电影数据网站,无反爬,无 HTTPS 证书,适合用作 HTTPS 证书验证。
分析:这里使用request库,直接参考代码即可

import requests
from lxml import etree

'''
ScrapeCenter ssr1 & ssr2
'''

# 数组url
urls = ["https://ssr1.scrape.center/page/{}".format(i) for i in range(1,11)]

# 用于去除返回的数组中的空格
def getText(list):
    try:
        return list[0].strip()
    except:
        return ""

for url in urls:
    # 请求目标地址
    response = requests.get(url)
    print(response.status_code)
    # 解析数据
    html = etree.HTML(response.text)
    # 定位data列表
    data_list = html.xpath('//*[@id="index"]/div[1]/div[1]/div')
    print(len(data_list))
    for data in data_list:
        print(data.text)
        img_src = getText(data.xpath('./div/div/div[1]/a/img/@src'))
        title = getText(data.xpath('./div/div/div[2]/a/h2/text()'))
        types = data.xpath('./div/div/div[2]/div[1]/button/span/text()')
        position = getText(data.xpath('./div/div/div[2]/div[2]/span[1]/text()'))
        total = getText(data.xpath('./div/div/div[2]/div[2]/span[3]/text()'))
        release = getText(data.xpath('./div/div/div[2]/div[3]/span/text()'))
        score = getText(data.xpath('./div/div/div[3]/p[1]/text()'.strip()))
        print(img_src, title, types, position, total, release, score)

srr3

案例ssr3:电影数据网站,无反爬,带有 HTTP BasicAuthentication,适合用作 HTTP 认证案例,用户名密码均为 admin。
带有 HTTPBasic Authentication,Python的requests库中,可以使用auth参数来指定Basic Auth的凭据。requests.auth.HTTPBasicAuth类允许你传递用户名和密码。

import requests
from lxml import etree
from requests.auth import HTTPBasicAuth

'''
ScrapeCenter ssr3
'''

# 数组url
urls = ["https://ssr3.scrape.center/page/{}".format(i) for i in range(1,11)]

# 用户名和密码
username = 'admin'
password = 'admin'

# 用于去除返回的数组中的空格
def getText(list):
    try:
        return list[0].strip()
    except:
        return ""

for url in urls:
    # 请求目标地址
    response = requests.get(url,auth=HTTPBasicAuth(username,password))
    print(response.status_code)
    # 解析数据
    html = etree.HTML(response.text)
    # 定位data列表
    data_list = html.xpath('//*[@id="index"]/div[1]/div[1]/div')
    print(len(data_list))
    for data in data_list:
        print(data.text)
        img_src = getText(data.xpath('./div/div/div[1]/a/img/@src'))
        title = getText(data.xpath('./div/div/div[2]/a/h2/text()'))
        types = data.xpath('./div/div/div[2]/div[1]/button/span/text()')
        position = getText(data.xpath('./div/div/div[2]/div[2]/span[1]/text()'))
        total = getText(data.xpath('./div/div/div[2]/div[2]/span[3]/text()'))
        release = getText(data.xpath('./div/div/div[2]/div[3]/span/text()'))
        score = getText(data.xpath('./div/div/div[3]/p[1]/text()'.strip()))
        print(img_src, title, types, position, total, release, score)

ssr4

案例ssr4:电影数据网站,无反爬,每个响应增加了5秒延迟,适合测试慢速网站爬取或做爬取速度测试,减少网速干扰。
分析:每个响应增加5s延迟,直接time.sleep(5)即可

import time

import requests
from anyio import sleep
from lxml import etree

'''
ScrapeCenter ssr4
'''

# 数组url
urls = ["https://ssr4.scrape.center/page/{}".format(i) for i in range(1,11)]


# 用于去除返回的数组中的空格
def getText(list):
    try:
        return list[0].strip()
    except:
        return ""

for url in urls:
    # 请求目标地址
    response = requests.get(url)
    time.sleep(5)
    print(response.status_code)
    # 解析数据
    html = etree.HTML(response.text)
    # 定位data列表
    data_list = html.xpath('//*[@id="index"]/div[1]/div[1]/div')
    print(len(data_list))
    for data in data_list:
        print(data.text)
        img_src = getText(data.xpath('./div/div/div[1]/a/img/@src'))
        title = getText(data.xpath('./div/div/div[2]/a/h2/text()'))
        types = data.xpath('./div/div/div[2]/div[1]/button/span/text()')
        position = getText(data.xpath('./div/div/div[2]/div[2]/span[1]/text()'))
        total = getText(data.xpath('./div/div/div[2]/div[2]/span[3]/text()'))
        release = getText(data.xpath('./div/div/div[2]/div[3]/span/text()'))
        score = getText(data.xpath('./div/div/div[3]/p[1]/text()'.strip()))
        print(img_src, title, types, position, total, release, score)

spa1

案例spa1:电影数据网站,无反爬,数据通过 Ajax 加载,页面动态渲染,适合 Ajax 分析和动态页面渲染爬取。
分析:需要使用selenium自动化,设置等待时间或者使用显式等待,等待页面数据渲染完毕。

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

'''
ScrapeCenter spa1
'''

# 数组url
urls = ["https://spa1.scrape.center/page/{}".format(i) for i in range(1,11)]
# 浏览器对象
driver = webdriver.Chrome()

for url in urls:
    driver.get(url)
    # 等待Ajax渲染完成(可配合显式等待优化)
    wait = WebDriverWait(driver, 10)
    # 设置判断条件:等待XPATH的元素加载完成
    wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="index"]/div[1]/div[1]/div')))
    data_list = driver.find_elements(By.XPATH,'//*[@id="index"]/div[1]/div[1]/div')
    for data in data_list:
        print(data.text)

driver.quit()

spa2

案例spa2:电影数据网站,无反爬,数据通过 Ajax 加载,数据接口参数加密且有时间限制,适合动态页面渲染爬取或 JavaScript 逆向分析。
分析:js逆向,打断点分析。

import execjs
import requests

'''
ScrapeCenter spa2
'''

with open('./spa2.js', 'r', encoding='utf-8') as f:
    js_code = f.read()
for j in range(0,110,10):
    token = execjs.compile(js_code).call("i",str(j))
    url = f"https://spa2.scrape.center/api/movie/?limit=10&offset={j}&token={token}"
    response = requests.get(url)
    print(response.status_code)
    print(response.text)

spa3

案例spa3:电影数据网站,无反爬,数据通过 Ajax 加载,无页码翻页,下拉至底部刷新,适合Ajax 分析和动态页面渲染爬取。
分析:Ajax进行数据加载,不使用翻页,通过下拉页面至底部进行刷新
up这里考虑了很久,尝试使用DrissionPage,但是也无法达到满意的效果
由于发现这个页面存在浏览器滚动条和DIV内嵌滚动条,这里需要对内嵌的DIV滚动条进行滚动,如果使用window.scrollxx进行滚动,都是滚动浏览器滚动条,无法实现加载新数据。

 import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

'''
ScrapeCenter spa3
'''
# 设置浏览器对象选项,确保开启javaScript
chrome_options = Options()
chrome_options.add_argument("--enable-javascript")
driver = webdriver.Chrome()
driver.get("https://spa3.scrape.center/")
# 这里的次数尝试一下,看滚动几次能够获取到所有的请求,这样所有的电影数据就全加载到页面了
for i in range(1, 4):
    print(f"第{i}次执行js")
    # js语句,可以先在页面控制台尝试如何进行滚动
    js = 'document.getElementById("index").scrollTop=document.getElementById("index").scrollHeight'
    result = driver.execute_script(js)
    time.sleep(2)

data_list = driver.find_elements(By.XPATH, '//*[@id="index"]/div/div/div')
print(len(data_list))
for data in data_list:
    print(data.text)
driver.quit()

spa4

案例spa4:新闻网站索引,无反爬,数据通过 Ajax 加载,无页码翻页,适合 Ajax 分析和动态页面渲染抓取以及智能页面提取分析。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

'''
ScrapeCenter spa4
'''
# 需要判断一下元素加载是否完成,不然太快无法爬取到数据
# 设置浏览器对象选项,确保开启javaScript
chrome_options = Options()
chrome_options.add_argument("--enable-javascript")
driver = webdriver.Chrome()
driver.get("https://spa4.scrape.center/")


# 等待Ajax渲染完成(可配合显式等待优化)
wait = WebDriverWait(driver, 10)
# 设置判断条件:等待XPATH的元素加载完成
wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="index"]/div/div/div')))
data_list = driver.find_elements(By.XPATH,'//*[@id="index"]/div/div/div')
print(len(data_list))
for data in data_list:
    print(data.text)

driver.quit()

spa5

案例spa5:图书网站,无反爬,数据通过 Ajax 加载,有翻页,适合大批量动态页面渲染抓取。
分析:卡住了,本来打算使用selenium等待数据渲染到页面,逐页爬取,发现爬不到,已经使用:WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, ‘//*[@id=“index”]/div[1]/div/div/div’))),但无法解决,随后通过使用time.slepp(1) 强制等待,又发现有的页中容易出现爬不到、爬不完整的情况,增加等待时间为2s,也容易存在爬不到的问题,并且还慢…。(已贴代码,有大佬可以帮忙分析一下原因,感谢~)
于是想到可以直接通过API获取,刚好这里没有对接口进行加密或鉴权。

import requests

'''
ScrapeCenter spa5
'''

urls = ["https://spa5.scrape.center/api/book/?limit=18&offset={}".format(i) for i in range(0,9037,18)]
i = 0
for url in urls:
    i += 1
    print(f"正在爬取第{i}页图书:")
    response = requests.get(url)
    data = response.json()  # 直接解析 JSON
    for data in data["results"]:
        list_author = data["authors"]
        # 使用列表推导式去除空格和换行
        authors = [x.replace('\n','').replace(' ','') for x in list_author]
        print(f"id:{data['id']},电影名:{data['name']},作者:{authors}")

# 以下为selenium
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

'''
ScrapeCenter spa5
'''

urls = ["https://spa5.scrape.center/page/{}".format(i) for i in range(1,504)]

driver = webdriver.Chrome()
for url in urls:
    driver.get(url)
    # 强制等待2s 不容易出现爬取不到的情况
    time.sleep(2)
    # 等待Ajax渲染完成(可配合显式等待优化)
    try:
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="index"]/div[1]/div/div/div'))
        )
    except:
        print("超时,未找到列表")
    data_list = driver.find_elements(By.XPATH,'//*[@id="index"]/div[1]/div/div/div')
    print(len(data_list))
    for data in data_list:
        print(data.text)

driver.quit()

spa6

案例spa6:电影数据网站,数据通过 Ajax 加载,数据接口参数加密且有时间限制,源码经过混淆,适合 JavaScript 逆向分析。

import base64
import execjs
import requests

'''
ScrapeCenter spa6
'''

with open('./spa6.js','r',encoding='utf-8') as f:
    file=f.read()
take=execjs.compile(file).call("_0x456254")
url_id=base64.b64encode(take.encode('utf-8'))
token=url_id.decode()
print(token)
urls = ["https://spa6.scrape.center/api/movie?limit=10&offset={}&token={}".format(i,token) for i in range(0,100,10)]
for url in urls:
    print(url)
    response = requests.get(url)
    print(response.status_code)
    data = response.json()
    for data in data['results']:
        print(data)

spa7 & spa8

案例spa7:NBA 球星数据网站,数据纯前端渲染Token 经过加密处理,适合基础 JavaScript模拟分析。
案例spa8:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript 代码一行混入 HTML代码,防止直接调试,适合JavaScript 逆向分析。
1、定义python方法进行加密解密

import base64
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad

'''
ScrapeCenter spa7 & spa8 & spa9 & spa10
'''

# 原始球员数据(JSON格式)
players =[
  {
    'name': '凯文-杜兰特',
    'image': 'durant.png',
    'birthday': '1988-09-29',
    'height': '208cm',
    'weight': '108.9KG'
  }, {
    'name': '勒布朗-詹姆斯',
    'image': 'james.png',
    'birthday': '1984-12-30',
    'height': '206cm',
    'weight': '113.4KG'
  }, {
    'name': '斯蒂芬-库里',
    'image': 'curry.png',
    'birthday': '1988-03-14',
    'height': '191cm',
    'weight': '83.9KG'
  }, {
    'name': '詹姆斯-哈登',
    'image': 'harden.png',
    'birthday': '1989-08-26',
    'height': '196cm',
    'weight': '99.8KG'
  }, {
    'name': '扬尼斯-安特托昆博',
    'image': 'antetokounmpo.png',
    'birthday': '1994-12-06',
    'height': '211cm',
    'weight': '109.8KG'
  }, {
    'name': '拉塞尔-威斯布鲁克',
    'image': 'westbrook.png',
    'birthday': '1988-11-12',
    'height': '191cm',
    'weight': '90.7KG'
  }, {
    'name': '凯里-欧文',
    'image': 'irving.png',
    'birthday': '1992-03-23',
    'height': '188cm',
    'weight': '88.5KG'
  }, {
    'name': '安东尼-戴维斯',
    'image': 'davis.png',
    'birthday': '1993-03-11',
    'height': '208cm',
    'weight': '114.8KG'
  }, {
    'name': '乔尔-恩比德',
    'image': 'embiid.png',
    'birthday': '1994-03-16',
    'height': '213cm',
    'weight': '127.0KG'
  }, {
    'name': '克雷-汤普森',
    'image': 'thompson.png',
    'birthday': '1990-02-08',
    'height': '198cm',
    'weight': '97.5KG'
  }, {
    'name': '考瓦伊-莱昂纳德',
    'image': 'leonard.png',
    'birthday': '1991-06-29',
    'height': '201cm',
    'weight': '102.1KG'
  }, {
    'name': '达米安-利拉德',
    'image': 'lillard.png',
    'birthday': '1990-07-15',
    'height': '188cm',
    'weight': '88.5KG'
  }, {
    'name': '卡梅罗-安东尼',
    'image': 'anthony.png',
    'birthday': '1984-05-29',
    'height': '203cm',
    'weight': '108KG'
  }, {
    'name': '尼科拉-约基奇',
    'image': 'jokic.png',
    'birthday': '1995-02-19',
    'height': '213cm',
    'weight': '128.8KG'
  }, {
    'name': '卡尔-安东尼-唐斯',
    'image': 'towns.png',
    'birthday': '1995-11-15',
    'height': '211cm',
    'weight': '112.5KG'
  }, {
    'name': '克里斯-保罗',
    'image': 'paul.png',
    'birthday': '1985-05-06',
    'height': '185cm',
    'weight': '79.4KG'
  },
]

# 密钥(截取前8字节)
SECRET_KEY = 'fipFfVsZsTda94hJNKJfLoaqyqMZFFimwLt'[:8].encode('utf-8')


def get_token(player):
    """生成球员的DES加密令牌"""
    # 将name转为Base64
    base64_name = base64.b64encode(player['name'].encode('utf-8')).decode('utf-8')

    # 拼接明文
    plaintext = f"{base64_name}{player['birthday']}{player['height']}{player['weight']}"
    plain_bytes = plaintext.encode('utf-8')

    # DES加密(ECB模式 + PKCS7填充)
    cipher = DES.new(SECRET_KEY, DES.MODE_ECB)
    padded_bytes = pad(plain_bytes, 8)  # PKCS7填充到8字节倍数
    encrypted = cipher.encrypt(padded_bytes)

    # 返回Base64编码结果
    return base64.b64encode(encrypted).decode('utf-8')


# 示例使用
if __name__ == "__main__":
    # 为每个球员生成token
    for player in players:
        token = get_token(player)
        print(f"{player['name']} 的Token: {token}")

2、调用js文件

import execjs

'''
ScrapeCenter spa7 & spa8 & spa9 & spa10 & spa11 & spa12
'''

# 测试数据
player = {
    'name': '勒布朗-詹姆斯',
    'image': 'james.png',
    'birthday': '1984-12-30',
    'height': '206cm',
    'weight': '113.4KG'
}

with open('js/spa7.js', 'r', encoding='utf-8') as f:
    file=f.read()
take=execjs.compile(file).call("getToken",player)
print(take)
const CryptoJS = require("crypto-js")

function getToken(player) {
    let key = CryptoJS.enc.Utf8.parse("fipFfVsZsTda94hJNKJfLoaqyqMZFFimwLt");
    const {name, birthday, height, weight} = player;
    let base64Name = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(name));
    let encrypted = CryptoJS.DES.encrypt(`${base64Name}${birthday}${height}${weight}`, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
}

spa9

案例spa9:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript 经过 eval混淆,适台 JavaScript 逆向分析。
分析:eval混淆,查看eval函数定义:
在这里插入图片描述
定义函数,并执行,查看返回的数据:
在这里插入图片描述
查看返回的数据(与spa7、spa8一致):
在这里插入图片描述

spa10

JJ解密加密:http://www.liminba.com/tool/jjencode/

案例spa10:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript 经过JJEncode 混淆,适合 JavaScript 逆向分析。
分析:JJEncode混淆,包含很多$,常见就是Function自执行函数,去掉代码最后的()并在控制台输出,即可进入虚拟机显示明文代码;也可以使用加密解密网站。
在这里插入图片描述
双击输出的结果,进入虚拟机查看明文代码
在这里插入图片描述

spa11

AA加密解密:

案例spa11:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript 经过AAEncode 混淆,适合 JavaScript 逆向分析。
分析:AAEncode 混淆,包含很多颜文字符号,处理方法同上;也可以使用加密解密网站。
在这里插入图片描述
双击输出的结果,进入虚拟机查看明文代码
在这里插入图片描述

spa12

JSFuck解密:http://www.liminba.com/tool/jsfuckdecode/

案例spa12:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript经过JSFuck 混淆,适合 JavaScript 逆向分析。
分析:JSFuck混淆,包含很多[],处理方法与上方相似,注意处理最后一个括号。可以复制到IDE工具中比较好找到对应的正括号;也可以使用解密网站。
在这里插入图片描述

spa13

案例spa13:NBA 球星数据网站,数据纯前端渲染,Token 经过加密处理,JavaScript 经过JavaScript Obfuscator 混淆,适合JavaScript 逆向分析。
分析:JavaScript Obfuscator 混淆,包含很多_0x数字字母,理解难度大。

这里暂时跳过…后续变强再回来!

spa14

案例spa14:电影数据网站,数据通过 Ajax 加载,数据接口参数加密且有时间限制,加密过程通过数值型 WASM 实现,适合 WASM 逆向分析。
分析:WebAssembly (简称Wasm) 是一种新型的低级二进制格式,为现代Web应用程序提供高性能的执行环境。wasm 是js可执行的一个扩展文件,我们使用python模拟执行此文件进行逆向分析。
将此wasm文件另存到本地。
在这里插入图片描述
断点进行分析
在这里插入图片描述

import time
import pywasm

'''
ScrapeCenter spa14
'''

def encrypt(n,t):
    runtime = pywasm.core.Runtime()
    m = runtime.instance_from_file('./js/Wasm.wasm')
    sign = runtime.invocate(m, 'encrypt', [n, t])
    # 得到的sign是一个数组,可以在这返回指定下标得到具体值
    return sign[0]

def get_sign():
    for n in range(1,11):
        t = int(time.time())
        sign = encrypt(n,t)
        print(f"第{n}页的sign为{sign}")

if __name__ == '__main__':
    get_sign()

spa15

spa15这里参考:https://blog.csdn.net/weixin_42065546/article/details/145586249

案例spa15:电影数据网站,数据通过 Ajax 加载,数据接口参数加密且有时间限制,加密过程通过字符串型 WASM 实现,适合 WASM 逆向分析。
分析:断点调试没有成功,参考了实现过程,最后逆向成功。

import base64
import hashlib
import requests
import time


'''
ScrapeCenter spa15
'''

uri = '/api/movie'
timestamp = int(time.time())
hashhex = hashlib.sha1(f'{uri},{timestamp}'.encode('utf-8')).hexdigest()
sign = base64.b64encode(f'{hashhex},{timestamp}'.encode('utf-8'))
print('sign: ', sign.decode('utf-8'))
token = sign.decode('utf-8')

url = f"https://spa15.scrape.center/api/movie?limit=10&offset=10&token={token}"
res = requests.get(url)
print(res.status_code)
print(res.text)

spa16

httpx官方在线文档:https://www.python-httpx.org/http2/

案例spa16:图书网站,无反爬,不同于其他,该网站协议采用 HTTP 2,适合用于 HTTP 2 协议分析和测试。
分析:python中requests库支持HTTP1.x,并不支持HTTP2,所以我们需要使用支持HTTP2的库HTTPX,使用终端安装httpx,请在终端命令行执行:pip install httpx[http2]

import httpx

'''
ScrapeCenter spa16
'''

url = 'https://spa16.scrape.center/api/book/'
client = httpx.Client(http2=True)
res = client.get(url)
print(res.text)
data = res.json()
for data in data["results"]:
    print(data)

captcha1

案例网址:https://captcha1.scrape.center/

案例:对接滑动拼图验证码,适合滑动拼图验证码分析处理。
分析:使用Selenium自动化,由于这里不能直接下载验证码图片,使用元素的screenshot方法进行截图保存,并分别计算缺口、滑块的x轴距离,结合ActionChains实现模拟连续的鼠标操作,模拟人类“先快后慢”的拖动轨迹,提高验证通过率。当然这种情况不能够实现100%通过。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import time


# 获取滑块、缺口以及完整图
def get_img():
    # (1)隐藏滑块  得到缺口图
    js_hide_hk = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="none"'
    driver.execute_script(js_hide_hk)
    # 截取缺口图
    qk_img = "./img/captcha1-qk.png"
    driver.find_element(By.CLASS_NAME, "geetest_canvas_bg").screenshot(qk_img)
    # (2)显示滑块  隐藏缺口图  得到滑块图
    js_show_hk = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="block"'
    js_hide_qk = 'document.getElementsByClassName("geetest_canvas_bg")[0].style.display="none"'
    driver.execute_script(js_show_hk + ";" + js_hide_qk)
    # 截取滑块图
    hk_img = "./img/captcha1-hk.png"
    driver.find_element(By.CLASS_NAME, "geetest_canvas_slice").screenshot(hk_img)
    # (3)显示完整图
    js_show_wz1 = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="block"'
    js_show_wz2 = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.opacity="1"'
    driver.execute_script(js_show_wz1 + ";" + js_show_wz2)
    # 截取完整图
    wz_img = "./img/captcha1-wz.png"
    driver.find_element(By.CLASS_NAME, "geetest_canvas_fullbg").screenshot(wz_img)
    # 还原  目的 还原成原来的模样  包含缺口图与滑块
    js_hide_wz1 = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="none"'
    js_hide_wz2 = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.opacity="0"'
    js_show_qk = 'document.getElementsByClassName("geetest_canvas_bg")[0].style.display="block"'
    driver.execute_script(js_hide_wz1 + ";" + js_hide_wz2 + ";" + js_show_qk)
    return hk_img, qk_img, wz_img


# 获取滑块的x轴坐标
def get_hk_x(hk_img):
    hk = Image.open(hk_img)
    w, h = hk.size
    for x in range(w):
        for y in range(h):
            rgb = hk.getpixel((x, y))  # (255,255,255)
            if rgb[0] + rgb[1] + rgb[2] < 600:
                print("滑块的坐标", x)
                return x


# 获取缺口的x轴坐标
def get_qk_x(qk_img, wz_img):
    qk = Image.open(qk_img)
    wz = Image.open(wz_img)
    w, h = qk.size
    for x in range(w):
        for y in range(h):
            qk_point = qk.getpixel((x, y))
            wz_point = wz.getpixel((x, y))
            r = qk_point[0] - wz_point[0]
            g = qk_point[1] - wz_point[1]
            b = qk_point[2] - wz_point[2]
            abs_value = abs(r) + abs(g) + abs(b)  # 33
            if abs_value > 180:
                print("缺口的坐标", x)
                return x

# 计算滑动距离
def get_distance(hk_img, qk_img, wz_img):
    hk_x = get_hk_x(hk_img)
    qk_x = get_qk_x(qk_img, wz_img)
    data = abs(hk_x - qk_x)
    print('计算距离', data)
    return data


# 滑动
def move(tracks):
    # 确定滑块对象
    element = driver.find_element(by=By.CLASS_NAME, value='geetest_slider_button')
    action_chains = ActionChains(driver)
    # 执行滑块的动作
    action_chains.click_and_hold(element).perform()
    action_chains.pause(0.2)
    action_chains.move_by_offset(tracks - 10, 0)  #
    action_chains.pause(0.6)
    action_chains.move_by_offset(10, 0)  #
    action_chains.pause(0.6)
    action_chains.release().perform()

if __name__ == '__main__':
    driver = webdriver.Chrome()
    url = 'https://captcha1.scrape.center/'
    driver.get(url)

    driver.find_elements(By.CLASS_NAME, 'el-input__inner')[0].send_keys("admin")
    driver.find_elements(By.CLASS_NAME, 'el-input__inner')[1].send_keys("admin")
    # 需要等待一下,太快点击不弹验证
    time.sleep(2)
    driver.find_element(By.XPATH, '//*[@id="app"]/div[2]/div/div/div/div/div/form/div[3]/div/button').click()
    # 等待页面滑块元素出现
    (WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'geetest_wrap'))))
    hk_img, qk_img, wz_img = get_img()
    distance = get_distance(hk_img, qk_img, wz_img)
    move(distance)
    time.sleep(2)
    # 获取当前URL
    current_url = driver.current_url
    # 使用assert断言URL是否正确
    expected_url = "https://captcha1.scrape.center/success"
    assert current_url == expected_url, f"URL不匹配: 预期 {expected_url}, 实际 {current_url}"
    print("模拟登录完成!!!!")
    time.sleep(5)
    driver.quit()

captcha7

案例captcha7:对接普通图像验证码,干扰较少,适合OCR 识别。
分析:使用selenium完成自动化操作,pillow库读取img,tesserocr进行OCR识别,这里需要注意验证码识别并不是很准确,需要结合图像灰度处理或二值化可能会提高准确率。

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from PIL import Image
import tesserocr

'''
ScrapeCenter captcha17
'''

driver = webdriver.Chrome()
url = 'https://captcha7.scrape.center/'
driver.get(url)
time.sleep(2)  # 这里需要有一个停顿
driver.find_elements(By.CLASS_NAME,"el-input__inner")[0].send_keys("admin")
driver.find_elements(By.CLASS_NAME,"el-input__inner")[1].send_keys("admin")
# 获取验证码图片
img = "./captcha7.png"
driver.find_element(By.ID,"captcha").screenshot(img)
image = Image.open(img)
key = tesserocr.image_to_text(image)
print(key)
driver.find_elements(By.CLASS_NAME,"el-input__inner")[2].send_keys(key)
driver.find_element(By.XPATH,'//*[@id="app"]/div[2]/div/div/div/div/div/form/div[4]/div/button').click()

# 获取当前URL
current_url = driver.current_url
# 使用assert断言URL是否正确
expected_url = "https://captcha7.scrape.center/success"
assert current_url == expected_url, f"URL不匹配: 预期 {expected_url}, 实际 {current_url}"

antispider1

案例网址:https://antispider1.scrape.center/

案例:对接 WebDriver反爬,检测到使用WebDriver 就不显示页面,适合用作WebDriver 反爬练习。
分析:WebDriver反爬虫解决方案

import time
from selenium import webdriver

driver = webdriver.Chrome()
with open('./js/stealth.min.js', encoding='utf-8') as f:
    driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': f.read()})  # 在页面刚加载的时候执行JavaScript语句
url = 'https://antispider1.scrape.center/'
driver.get(url)
time.sleep(2)
print(driver.page_source)

antispider2

案例网址:https://antispider2.scrape.center/

案例:对接 User-Agent 反爬,检测到常见爬虫User-Agent 就会拒绝响应,适合用作 User-Agent 反爬练习。
分析:User-Agent反爬虫解决方案

import requests

url = 'https://antispider2.scrape.center/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}

response = requests.get(url, headers=headers)
print(response.text)

antispider3

案例网址:https://antispider3.scrape.center/

案例:对接文字偏移反爬,所见顺序并不一定和源码顺序一致,适合用作文字偏移反爬练习。
分析:selenium自动化结合pyquery网页解析,提取到所有的书名

import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from pyquery import PyQuery as pq


def parse(name):
    # 找到该h3下每个span的class名为char
    char = name(".char")
    results = []
    for char in char.items():
        # 追加到列表中为字典,形成映射
        results.append({"text": char.text().strip(),"left": int(re.search(r'left: (\d+)', char.attr('style')).group(1))})
    # 按照left键进行排序
    results = sorted(results, key=lambda i:i["left"], reverse=False)
    # 列表推导式将每个值拼接成完整的书名
    return ''.join([result.get('text') for result in results])

driver = webdriver.Chrome()
driver.get('https://antispider3.scrape.center/')
(WebDriverWait(driver,10).until(ec.presence_of_all_elements_located((By.CSS_SELECTOR,'.item'))))
html = driver.page_source
doc = pq(html)
# 获取class为 item .name
names = doc('.item .name')
print(len(names))
for name in names.items():
    if name(".char"):
        names = parse(name)
        print(names)
    else:
        print(name.text())

antispider4

案例网址:https://antispider4.scrape.center/

案例:对接字体文件反爬,显示的内容并不在HTML 内,而是隐藏在字体文件,设置了文字映射表,适合用作字体反爬练习。
分析:正常使用selenium可以爬取到数据,但是发现电影评分获取不到,针对电影评分做了文字字体反爬,需要解析出css对应的关系映射。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import re
import requests

# 这里解析css文件,找出对应的映射关系
response = requests.get('https://antispider4.scrape.center/css/app.654ba59e.css')
# 使用正则表达式匹配所有的目标规则
# ([\w-]+):捕获组1,匹配.icon-后的字母、数字或字符(如281、A),\w等价于[a-zA-Z0-9_]。
# "([^"]+)":捕获组2,匹配双引号内的任意非引号字符(如"3"、".")。
# \s*:匹配任意空白(空格、换行),增强对CSS格式变化的适应性
pattern = r'\.icon-([\w-]+):before\s*{\s*content:\s*"([^"]+)"\s*}'
results = re.findall(pattern, response.text)
# 构建字典
final_results = {item[0]: item[1] for item in results}
print(final_results)

driver = webdriver.Chrome()
driver.get('https://antispider4.scrape.center/')
(WebDriverWait(driver, 10)
 .until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item'))))
# 找到所有图书的div标签列表
data_list = driver.find_elements(By.XPATH, '//*[@id="index"]/div[1]/div[1]/div')
for d in data_list:
    print(d.text)
    # 找到span标签
    i = d.find_elements(By.XPATH, './/div/div/div[3]/p[1]/span')
    score = ''
    # 遍历每个span标签下的i标签
    for j in i:
        icon = j.find_element(By.XPATH,'.//i').get_attribute("class")
        # 直接匹配连字符后的数字
        match = re.search(r'icon-(\d+)', icon)
        if match:
            number = match.group(1)
            # 把键传入字典,得到值进行累加拼接
            name = final_results[number]
            score += name
    print(score)
driver.close()
driver.quit()

antispider9

案例网址:https://antispider9.scrape.center/

案例:对接字体文件反爬,显示的内容并不在HTML 内,而是隐藏在字体文件,设置了文字映射表,适合用作字体反爬练习。
分析:固定值:/api/movie与时间 r 合成数组n进行,拼接得到数据:“/api/movie,{r}” ,使用sha1加密得到c,c与时间r拼接成:“{c},{r}”,进行base64数据格式转换得到a
在这里插入图片描述

from hashlib import sha1
import base64

t = '1749710971'
r = f"/api/movie,{t}"
sha1_encode = sha1(r.encode('utf-8')).hexdigest()
data= f'{sha1_encode},{t}'

token = base64.b64encode(data.encode()).decode()
print(token)
❤如果文章对您有帮助,您的点赞就是我最大的动力❤
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐