mirror of https://github.com/aliasrobotics/cai.git
Merge branch 'aliasrobotics:main' into main
This commit is contained in:
commit
321e78b46e
238
README.md
238
README.md
|
|
@ -138,6 +138,7 @@ Cybersecurity AI is a critical field, yet many groups are misguidedly pursuing i
|
|||
- [CrackenAGI](https://cracken.ai/)
|
||||
- [ETHIACK](https://ethiack.com/)
|
||||
- [Horizon3](https://horizon3.ai/)
|
||||
- [Kindo](https://www.kindo.ai/)
|
||||
- [Lakera](https://lakera.ai)
|
||||
- [Mindfort](www.mindfort.ai)
|
||||
- [Mindgard](https://mindgard.ai/)
|
||||
|
|
@ -157,15 +158,27 @@ Cybersecurity AI is a critical field, yet many groups are misguidedly pursuing i
|
|||
|
||||
## Learn - `CAI` Fluency
|
||||
|
||||
<div align="center">
|
||||
<p>
|
||||
<a align="center" href="" target="https://github.com/aliasrobotics/CAI">
|
||||
<img
|
||||
width="100%"
|
||||
src="https://github.com/aliasrobotics/cai/raw/main/media/caiedu.PNG"
|
||||
>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
| | Description | English | Spanish |
|
||||
|-------|----------------|---------|---------|
|
||||
| **Episode 0**: What is CAI? | Cybersecurity AI (`CAI`) explained | [](https://www.youtube.com/watch?v=nBdTxbKM4oo) | [](https://www.youtube.com/watch?v=FaUL9HXrQ5k) |
|
||||
| **Episode 1**: The `CAI` Framework | Vision & Ethics - Explore the core motivation behind CAI and delve into the crucial ethical principles guiding its development. Understand the motivation behind CAI and how you can actively contribute to the future of cybersecurity and the CAI framework. | [](https://www.youtube.com/watch?v=QEiGdsMf29M&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=3) | |
|
||||
| **Episode 2**: Foundational Concepts | LLM Agents - Bridge the gap between foundational LLMs and intelligent agents, exploring how to synergize reasoning and acting for truly dynamic interactions. Learn about AI systems that don't just generate text, but actively interact within their environment. | *Coming soon* | *Coming soon* |
|
||||
| **Episode 2**: From Zero to Cyber Hero | Breaking into Cybersecurity with AI - A comprehensive guide for complete beginners to become cybersecurity practitioners using CAI and AI tools. Learn how to leverage artificial intelligence to accelerate your cybersecurity learning journey, from understanding basic security concepts to performing real-world security assessments, all without requiring prior cybersecurity experience. | [](https://www.youtube.com/watch?v=hSTLHOOcQoY&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=14) | |
|
||||
| **Episode 3**: Vibe-Hacking Tutorial | "My first Hack" - A Vibe-Hacking guide for newbies. We demonstrate a simple web security hack using a default agent and show how to leverage tools and interpret CIA output with the help of the CAI Python API. You'll also learn to compare different LLM models to find the best fit for your hacking endeavors. | [](https://www.youtube.com/watch?v=9vZ_Iyex7uI&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=1) | [](https://www.youtube.com/watch?v=iAOMaI1ftiA&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=2) |
|
||||
| **Episode 4**: Intro ReAct | The Evolution of LLMs - Learn how LLMs evolved from basic language models to advanced multiagency AI systems. From basic LLMs to Chain-of-Thought and Reasoning LLMs towards ReAct and Multi-Agent Architectures. Get to know the basic terms | *Coming soon* | *Coming soon* |
|
||||
| **Episode 5**: CAI on CTF challenges | Dive into Capture The Flag (CTF) competitions using CAI. Learn how to leverage AI agents to solve various cybersecurity challenges including web exploitation, cryptography, reverse engineering, and forensics. Discover how to configure CAI for competitive hacking scenarios and maximize your CTF performance with intelligent automation. | *Coming soon* | *Coming soon* |
|
||||
| **Episode 4**: Intro ReAct | The Evolution of LLMs - Learn how LLMs evolved from basic language models to advanced multiagency AI systems. From basic LLMs to Chain-of-Thought and Reasoning LLMs towards ReAct and Multi-Agent Architectures. Get to know the basic terms | [](https://www.youtube.com/watch?v=tLdFO1flj_o&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=13) | |
|
||||
| **Episode 5**: CAI on CTF challenges | Dive into Capture The Flag (CTF) competitions using CAI. Learn how to leverage AI agents to solve various cybersecurity challenges including web exploitation, cryptography, reverse engineering, and forensics. Discover how to configure CAI for competitive hacking scenarios and maximize your CTF performance with intelligent automation. | [](https://www.youtube.com/watch?v=MrXTQ0e2to4&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=13) | [](https://www.youtube.com/watch?v=r9US_JZa9_c&list=PLLc16OUiZWd4RuFdN5_Wx9xwjCVVbopzr&index=12) |
|
||||
| **Episode 6**: CAI Fluency Framework | Introducing CAI Fluency: An Educational Framework for Cybersecurity AI - Learn about the comprehensive educational platform designed to democratize cybersecurity AI knowledge. Explore the theoretical foundations, the 4 C's competencies (Command, Communication, Critique, Custody), and the three modalities of Human-AI interaction in security contexts. | *Coming soon* | *Coming soon* |
|
||||
| | | | |
|
||||
| **Annex 1**: `CAI` 0.5.x release | Introduce version 0.5 of `CAI` including new multi-agent functionality, new commands such as `/history`, `/compact`, `/graph` or `/memory` and a case study showing how `CAI` found a critical security flaw in OT heap pumps spread around the world. | [](https://www.youtube.com/watch?v=OPFH0ANUMMw) | [](https://www.youtube.com/watch?v=Q8AI4E4gH8k) |
|
||||
| **Annex 2**: `CAI` 0.4.x release and `alias0` | Introducing version 0.4 of `CAI` with *streaming* and improved MCP support. We also introduce `alias0`, the Privacy-First Cybersecurity AI, a Model-of-Models Intelligence that implements a Privacy-by-Design architecture and obtains state-of-the-art results in cybersecurity benchmarks. | [](https://www.youtube.com/watch?v=NZjzfnvAZcc) | |
|
||||
|
|
@ -377,90 +390,70 @@ CAI focuses on making cybersecurity agent **coordination** and **execution** lig
|
|||
|
||||
If you want to dive deeper into the code, check the following files as a start point for using CAI:
|
||||
|
||||
```
|
||||
cai
|
||||
├── __init__.py
|
||||
│
|
||||
├── cli.py # entrypoint for CLI
|
||||
├── core.py # core implementation and agentic flow
|
||||
├── types.py # main abstractions and classes
|
||||
├── util.py # utility functions
|
||||
│
|
||||
├── repl # CLI aesthetics and commands
|
||||
│ ├── commands
|
||||
│ └── ui
|
||||
├── agents # agent implementations
|
||||
│ ├── one_tool.py # agent, one agent per file
|
||||
│ └── patterns # agentic patterns, one per file
|
||||
│
|
||||
├── tools # agent tools
|
||||
│ ├── common.py
|
||||
|
||||
caiextensions # out of tree Python extensions
|
||||
```
|
||||
|
||||
* [__init__.py](https://github.com/aliasrobotics/cai/blob/main/src/cai/__init__.py)
|
||||
* [cli.py](https://github.com/aliasrobotics/cai/blob/main/src/cai/cli.py) - entrypoint for command line interface
|
||||
* [util.py](https://github.com/aliasrobotics/cai/blob/main/src/cai/util.py) - utility functions
|
||||
* [agents](https://github.com/aliasrobotics/cai/blob/main/src/cai/agents) - Agent implementations
|
||||
* [internal](https://github.com/aliasrobotics/cai/blob/main/src/cai/internal) - CAI internal functions (endpoints, metrics, logging, etc.)
|
||||
* [prompts](https://github.com/aliasrobotics/cai/blob/main/src/cai/prompts) - Agent Prompt Database
|
||||
* [repl](https://github.com/aliasrobotics/cai/blob/main/src/cai/repl) - CLI aesthetics and commands
|
||||
* [sdk](https://github.com/aliasrobotics/cai/blob/main/src/cai/sdk) - CAI command sdk
|
||||
* [tools](https://github.com/aliasrobotics/cai/tree/main/src/cai/tools) - agent tools
|
||||
|
||||
### 🔹 Agent
|
||||
|
||||
At its core, CAI abstracts its cybersecurity behavior via `Agents` and agentic `Patterns`. An Agent in *an intelligent system that interacts with some environment*. More technically, within CAI we embrace a robotics-centric definition wherein an agent is anything that can be viewed as a system perceiving its environment through sensors, reasoning about its goals and and acting accordingly upon that environment through actuators (*adapted* from Russel & Norvig, AI: A Modern Approach). In cybersecurity, an `Agent` interacts with systems and networks, using peripherals and network interfaces as sensors, reasons accordingly and then executes network actions as if actuators. Correspondingly, in CAI, `Agent`s implement the `ReACT` (Reasoning and Action) agent model[^3].
|
||||
|
||||
At its core, CAI abstracts its cybersecurity behavior via `Agents` and agentic `Patterns`. An Agent in *an intelligent system that interacts with some environment*. More technically, within CAI we embrace a robotics-centric definition wherein an agent is anything that can be viewed as a system perceiving its environment through sensors, reasoning about its goals and and acting accordingly upon that environment through actuators (*adapted* from Russel & Norvig, AI: A Modern Approach). In cybersecurity, an `Agent` interacts with systems and networks, using peripherals and network interfaces as sensors, reasons accordingly and then executes network actions as if actuators. Correspondingly, in CAI, `Agent`s implement the `ReACT` (Reasoning and Action) agent model[^3]. For more information, see the [example here](https://github.com/aliasrobotics/cai/blob/main/examples/basic/hello_world.py) for the full execution code, and refer to this [jupyter notebook](https://github.com/aliasrobotics/cai/blob/main/fluency/my-first-hack/my_first_hack.ipynb) for a tutorial on how to use it.
|
||||
|
||||
```python
|
||||
from cai.sdk.agents import Agent
|
||||
from cai.core import CAI
|
||||
ctf_agent = Agent(
|
||||
name="CTF Agent",
|
||||
instructions="""You are a Cybersecurity expert Leader""",
|
||||
model= "gpt-4o",
|
||||
)
|
||||
from cai.sdk.agents import Agent, Runner, OpenAIChatCompletionsModel
|
||||
|
||||
messages = [{
|
||||
"role": "user",
|
||||
"content": "CTF challenge: TryMyNetwork. Target IP: 192.168.1.1"
|
||||
}]
|
||||
import os
|
||||
from openai import AsyncOpenAI
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
client = CAI()
|
||||
response = client.run(agent=ctf_agent,
|
||||
messages=messages)
|
||||
agent = Agent(
|
||||
name="Custom Agent",
|
||||
instructions="""You are a Cybersecurity expert Leader""",
|
||||
model=OpenAIChatCompletionsModel(
|
||||
model=os.getenv('CAI_MODEL', "openai/gpt-4o"),
|
||||
openai_client=AsyncOpenAI(),
|
||||
)
|
||||
)
|
||||
|
||||
message = "Tell me about recursion in programming."
|
||||
result = await Runner.run(agent, message)
|
||||
```
|
||||
|
||||
### 🔹 Tools
|
||||
|
||||
`Tools` let cybersecurity agents take actions by providing interfaces to execute system commands, run security scans, analyze vulnerabilities, and interact with target systems and APIs - they are the core capabilities that enable CAI agents to perform security tasks effectively; in CAI, tools include built-in cybersecurity utilities (like LinuxCmd for command execution, WebSearch for OSINT gathering, Code for dynamic script execution, and SSHTunnel for secure remote access), function calling mechanisms that allow integration of any Python function as a security tool, and agent-as-tool functionality that enables specialized security agents (such as reconnaissance or exploit agents) to be used by other agents, creating powerful collaborative security workflows without requiring formal handoffs between agents.
|
||||
`Tools` let cybersecurity agents take actions by providing interfaces to execute system commands, run security scans, analyze vulnerabilities, and interact with target systems and APIs - they are the core capabilities that enable CAI agents to perform security tasks effectively; in CAI, tools include built-in cybersecurity utilities (like LinuxCmd for command execution, WebSearch for OSINT gathering, Code for dynamic script execution, and SSHTunnel for secure remote access), function calling mechanisms that allow integration of any Python function as a security tool, and agent-as-tool functionality that enables specialized security agents (such as reconnaissance or exploit agents) to be used by other agents, creating powerful collaborative security workflows without requiring formal handoffs between agents. For more information, please refer to the [example here](https://github.com/aliasrobotics/cai/blob/main/examples/basic/tools.py) for the complete configuration of custom functions.
|
||||
|
||||
```python
|
||||
from cai.sdk.agents import Agent
|
||||
from cai.tools.common import run_command
|
||||
from cai.core import CAI
|
||||
from cai.sdk.agents import Agent, Runner, OpenAIChatCompletionsModel
|
||||
from cai.tools.reconnaissance.exec_code import execute_code
|
||||
from cai.tools.reconnaissance.generic_linux_command import generic_linux_command
|
||||
|
||||
def listing_tool():
|
||||
"""
|
||||
This is a tool used list the files in the current directory
|
||||
"""
|
||||
command = "ls -la"
|
||||
return run_command(command, ctf=ctf)
|
||||
import os
|
||||
from openai import AsyncOpenAI
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
def generic_linux_command(command: str = "", args: str = "", ctf=None) -> str:
|
||||
"""
|
||||
Tool to send a linux command.
|
||||
"""
|
||||
command = f'{command} {args}'
|
||||
return run_command(command, ctf=ctf)
|
||||
agent = Agent(
|
||||
name="Custom Agent",
|
||||
instructions="""You are a Cybersecurity expert Leader""",
|
||||
tools= [
|
||||
generic_linux_command,
|
||||
execute_code
|
||||
],
|
||||
model=OpenAIChatCompletionsModel(
|
||||
model=os.getenv('CAI_MODEL', "openai/gpt-4o"),
|
||||
openai_client=AsyncOpenAI(),
|
||||
)
|
||||
)
|
||||
|
||||
ctf_agent = Agent(
|
||||
name="CTF Agent",
|
||||
instructions="""You are a Cybersecurity expert Leader""",
|
||||
model= "claude-3-7-sonnet-20250219",
|
||||
functions=[listing_tool, generic_linux_command])
|
||||
|
||||
client = CAI()
|
||||
messages = [{
|
||||
"role": "user",
|
||||
"content": "CTF challenge: TryMyNetwork. Target IP: 192.168.1.1"
|
||||
}]
|
||||
|
||||
response = client.run(agent=ctf_agent,
|
||||
messages=messages)
|
||||
message = "Tell me about recursion in programming."
|
||||
result = await Runner.run(agent, message)
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -476,43 +469,47 @@ You may find different [tools](cai/tools). They are grouped in 6 major categorie
|
|||
|
||||
### 🔹 Handoffs
|
||||
|
||||
`Handoffs` allow an `Agent` to delegate tasks to another agent, which is crucial in cybersecurity operations where specialized expertise is needed for different phases of an engagement. In our framework, `Handoffs` are implemented as tools for the LLM, where a **handoff/transfer function** like `transfer_to_flag_discriminator` enables the `ctf_agent` to pass control to the `flag_discriminator_agent` once it believes it has found the flag. This creates a security validation chain where the first agent handles exploitation and flag discovery, while the second agent specializes in flag verification, ensuring proper segregation of duties and leveraging specialized capabilities of different models for distinct security tasks.
|
||||
`Handoffs` allow an `Agent` to delegate tasks to another agent, which is crucial in cybersecurity operations where specialized expertise is needed for different phases of an engagement. In our framework, `Handoffs` are implemented as tools for the LLM, where a **handoff/transfer function** like `transfer_to_flag_discriminator` enables the `ctf_agent` to pass control to the `flag_discriminator_agent` once it believes it has found the flag. This creates a security validation chain where the first agent handles exploitation and flag discovery, while the second agent specializes in flag verification, ensuring proper segregation of duties and leveraging specialized capabilities of different models for distinct security tasks. For more information, please refer to the [example here](https://github.com/aliasrobotics/cai/blob/main/examples/cai/agent_patterns/handoffs.py) for the full execution code.
|
||||
|
||||
|
||||
```python
|
||||
from cai.sdk.agents import Agent
|
||||
from cai.core import CAI
|
||||
from cai.sdk.agents import function_tool
|
||||
from cai.tools.common import run_command
|
||||
from cai.sdk.agents import Agent, OpenAIChatCompletionsModel, HandoffInputData, Runner, function_tool, handoff, trace
|
||||
from cai.sdk.agents.extensions import handoff_filters
|
||||
|
||||
import os
|
||||
from openai import AsyncOpenAI
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
@function_tool
|
||||
def execute_cli_command(command: str) -> str:
|
||||
return run_command(command)
|
||||
|
||||
flag_discriminator = Agent(
|
||||
name="Flag discriminator",
|
||||
description="Agent focused on extracting the flag from the output",
|
||||
instructions="You are an agent tailored to extract the flag from a given output.",
|
||||
model=OpenAIChatCompletionsModel(
|
||||
model=os.getenv('CAI_MODEL', "qwen2.5:14b"),
|
||||
openai_client=AsyncOpenAI(),
|
||||
)
|
||||
)
|
||||
|
||||
ctf_agent = Agent(
|
||||
name="CTF Agent",
|
||||
instructions="""You are a Cybersecurity expert Leader""",
|
||||
model= "deepseek/deepseek-chat",
|
||||
functions=[],
|
||||
name="CTF agent",
|
||||
description="Agent focused on conquering security challenges",
|
||||
instructions="You are a Cybersecurity expert Leader facing a CTF",
|
||||
tools=[
|
||||
execute_cli_command,
|
||||
],
|
||||
model=OpenAIChatCompletionsModel(
|
||||
model= os.getenv('CAI_MODEL', "qwen2.5:14b"),
|
||||
openai_client=AsyncOpenAI(),
|
||||
),
|
||||
handoffs = [flag_discriminator]
|
||||
)
|
||||
|
||||
flag_discriminator_agent = Agent(
|
||||
name="Flag Discriminator Agent",
|
||||
instructions="You are a Cybersecurity expert facing a CTF challenge. You are in charge of checking if the flag is correct.",
|
||||
model= "qwen2.5:14b",
|
||||
functions=[],
|
||||
)
|
||||
|
||||
def transfer_to_flag_discriminator():
|
||||
"""
|
||||
Transfer the flag to the flag_discriminator_agent to check if it is the correct flag
|
||||
"""
|
||||
return flag_discriminator_agent
|
||||
|
||||
ctf_agent.functions.append(transfer_to_flag_discriminator)
|
||||
|
||||
client = CAI()
|
||||
messages = [{
|
||||
"role": "user",
|
||||
"content": "CTF challenge: TryMyNetwork. Target IP: 192.168.1.1"
|
||||
}]
|
||||
|
||||
response = client.run(agent=ctf_agent,
|
||||
messages=messages)
|
||||
```
|
||||
|
||||
### 🔹 Patterns
|
||||
|
|
@ -544,44 +541,9 @@ When building `Patterns`, we generall y classify them among one of the following
|
|||
| `Auction-Based` (Competitive Allocation) | Agents "bid" on tasks based on priority, capability, or cost. A decision agent evaluates bids and hands off tasks to the best-fit agent. |
|
||||
| `Recursive` | A single agent continuously refines its own output, treating itself as both executor and evaluator, with handoffs (internal or external) to itself. *An example of a recursive agentic pattern is the `CodeAgent` (when used as a recursive agent), which continuously refines its own output by executing code and updating its own instructions.* |
|
||||
|
||||
Building a `Pattern` is rather straightforward and only requires to link together `Agents`, `Tools` and `Handoffs`. For example, the following builds an offensive `Pattern` that adopts the `Swarm` category:
|
||||
|
||||
```python
|
||||
# A Swarm Pattern for Red Team Operations
|
||||
from cai.agents.red_teamer import redteam_agent
|
||||
from cai.agents.thought import thought_agent
|
||||
from cai.agents.mail import dns_smtp_agent
|
||||
For more information and examples of common agentic patterns, see the [examples folder](https://github.com/aliasrobotics/cai/blob/main/examples/agent_patterns/README.md).
|
||||
|
||||
|
||||
def transfer_to_dns_agent():
|
||||
"""
|
||||
Use THIS always for DNS scans and domain reconnaissance about dmarc and dkim registers
|
||||
"""
|
||||
return dns_smtp_agent
|
||||
|
||||
|
||||
def redteam_agent_handoff(ctf=None):
|
||||
"""
|
||||
Red Team Agent, call this function empty to transfer to redteam_agent
|
||||
"""
|
||||
return redteam_agent
|
||||
|
||||
|
||||
def thought_agent_handoff(ctf=None):
|
||||
"""
|
||||
Thought Agent, call this function empty to transfer to thought_agent
|
||||
"""
|
||||
return thought_agent
|
||||
|
||||
# Register handoff functions to enable inter-agent communication pathways
|
||||
redteam_agent.functions.append(transfer_to_dns_agent)
|
||||
dns_smtp_agent.functions.append(redteam_agent_handoff)
|
||||
thought_agent.functions.append(redteam_agent_handoff)
|
||||
|
||||
# Initialize the swarm pattern with the thought agent as the entry point
|
||||
redteam_swarm_pattern = thought_agent
|
||||
redteam_swarm_pattern.pattern = "swarm"
|
||||
```
|
||||
|
||||
### 🔹 Turns and Interactions
|
||||
During the agentic flow (conversation), we distinguish between **interactions** and **turns**.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ from selenium import webdriver
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.chrome.service import Service
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
import time
|
||||
import random
|
||||
import json
|
||||
|
|
@ -14,7 +16,7 @@ from pathlib import Path
|
|||
class Bot():
|
||||
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self,headless=True):
|
||||
"""
|
||||
Initializes the MyBrowser instance.
|
||||
Sets up Chrome WebDriver with headless mode and necessary arguments
|
||||
|
|
@ -24,8 +26,13 @@ class Bot():
|
|||
self.LABS_URL = 'https://portswigger.net/web-security/all-labs#'
|
||||
self.prefixes_filename = 'topics_prefixes.json'
|
||||
self.options = Options()
|
||||
|
||||
for arg in ['--headless','--disable-gpu', '--no-sandbox']:
|
||||
|
||||
if headless:
|
||||
args = ['--headless','--disable-gpu', '--no-sandbox']
|
||||
else:
|
||||
args = ['--disable-gpu', '--no-sandbox']
|
||||
|
||||
for arg in args:
|
||||
self.options.add_argument(arg)
|
||||
|
||||
self.driver = webdriver.Chrome(options=self.options)
|
||||
|
|
@ -76,7 +83,7 @@ class Bot():
|
|||
|
||||
|
||||
|
||||
def choose_topic(self,topic_name='sql-injection',level=None):
|
||||
def choose_topic(self,topic_name='cross-site-scripting',level=None):
|
||||
"""
|
||||
Extract urls of each of the labs in the selected section.
|
||||
|
||||
|
|
@ -99,9 +106,18 @@ class Bot():
|
|||
|
||||
#Go to sections urls
|
||||
self.driver.get(f'{self.LABS_URL}{topic_name}')
|
||||
self.__wait_random_time(min_seconds=5, max_seconds=7)
|
||||
|
||||
links = WebDriverWait(self.driver, 10).until(
|
||||
EC.presence_of_all_elements_located((By.CLASS_NAME, 'widgetcontainer-lab-link'))
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
#Find all <a> elements that have the topic prefix in the href
|
||||
links = self.driver.find_elements(By.CLASS_NAME, 'flex-columns')
|
||||
links = self.driver.find_elements(By.CLASS_NAME, 'widgetcontainer-lab-link')
|
||||
|
||||
|
||||
#Extract the href attributes
|
||||
if level:
|
||||
|
|
@ -110,7 +126,7 @@ class Bot():
|
|||
extracted_links = [link.find_element(By.TAG_NAME, 'a').get_attribute('href') for link in links]
|
||||
|
||||
#Filter links that contain the topic prefix
|
||||
return [link for link in extracted_links if topic_name == link.split('/')[4]]
|
||||
return [link for link in extracted_links if topic_prefix == link.split('/')[4]]
|
||||
|
||||
def obtain_lab_information(self,lab_url):
|
||||
"""
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Loading…
Reference in New Issue