-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrawl_docs_sequential.py
More file actions
153 lines (125 loc) · 4.83 KB
/
Copy pathcrawl_docs_sequential.py
File metadata and controls
153 lines (125 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
### Code Source
### https://github.com/coleam00/ottomator-agents/blob/main/crawl4AI-agent-v2/crawl4AI-examples/2-crawl_docs_sequential.py
import asyncio
from typing import List
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
import requests
from xml.etree import ElementTree
import os
from urllib.parse import urlparse
import re
def create_filename_from_url(url: str) -> str:
"""
Creates a filename from URL path after .com/
Args:
url (str): The full URL
Returns:
str: Filename for the content
"""
parsed = urlparse(url)
path = parsed.path
# Remove leading slash and replace remaining slashes with underscores
if path.startswith('/'):
path = path[1:]
if not path or path == '':
filename = 'index'
else:
filename = path.replace('/', '_').replace('\\', '_')
filename = re.sub(r'[^\w\-_.]', '_', filename)
if not filename.endswith('.md'):
filename += '.md'
return filename
def save_content_to_file(content: str, url: str, base_folder: str):
"""
Saves the scraped content to a file in the specified folder structure.
Args:
content (str): The markdown content to save
url (str): The original URL
base_folder (str): The base folder name (e.g., 'docs.flowiseai.com')
"""
try:
# Create the base folder if it doesn't exist
if not os.path.exists(base_folder):
os.makedirs(base_folder)
filename = create_filename_from_url(url)
filepath = os.path.join(base_folder, filename)
# Save the content
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
print(f"Saved content to: {filepath}")
except Exception as e:
print(f"Error saving content for {url}: {e}")
def extract_domain_from_sitemap_url(sitemap_url: str) -> str:
"""
Extracts the domain name from the sitemap URL to use as folder name.
Args:
sitemap_url (str): The sitemap URL
Returns:
str: Domain name to use as folder name
"""
parsed = urlparse(sitemap_url)
domain = parsed.netloc
return domain
async def crawl_sequential(urls: List[str], sitemap_url: str):
print("\n=== Sequential Crawling with Session Reuse ===")
# Extract folder name from sitemap URL
base_folder = extract_domain_from_sitemap_url(sitemap_url)
print(f"Saving content to folder: {base_folder}")
browser_config = BrowserConfig(
headless=True,
extra_args=["--disable-gpu", "--disable-dev-shm-usage", "--no-sandbox"],
)
crawl_config = CrawlerRunConfig(
markdown_generator=DefaultMarkdownGenerator()
)
# Create the crawler (opens the browser)
crawler = AsyncWebCrawler(config=browser_config)
await crawler.start()
try:
session_id = "session1"
for url in urls:
result = await crawler.arun(
url=url,
config=crawl_config,
session_id=session_id
)
if result.success:
print(f"Successfully crawled: {url}")
print(f"Markdown length: {len(result.markdown.raw_markdown)}")
save_content_to_file(result.markdown.raw_markdown, url, base_folder)
else:
print(f"Failed: {url} - Error: {result.error_message}")
finally:
await crawler.close()
def get_pydantic_ai_docs_urls():
"""
Fetches all URLs from the Pydantic AI documentation.
Uses the sitemap (https://ai.pydantic.dev/sitemap.xml) to get these URLs.
Returns:
List[str]: List of URLs
"""
sitemap_url = "https://docs.flowiseai.com/sitemap-pages.xml"
try:
response = requests.get(sitemap_url)
response.raise_for_status()
# Parse the XML
root = ElementTree.fromstring(response.content)
# Extract all URLs from the sitemap
# The namespace is usually defined in the root element
namespace = {'ns': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
urls = [loc.text for loc in root.findall('.//ns:loc', namespace)]
return urls
except Exception as e:
print(f"Error fetching sitemap: {e}")
return []
async def main():
sitemap_url = "https://docs.flowiseai.com/sitemap-pages.xml"
urls = get_pydantic_ai_docs_urls()
if urls:
print(f"Found {len(urls)} URLs to crawl")
await crawl_sequential(urls, sitemap_url)
else:
print("No URLs found to crawl")
if __name__ == "__main__":
asyncio.run(main())