diff --git a/.gitignore b/.gitignore index a9edce7..0c8f280 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,4 @@ tmp2.md .harmon_ai/README_template.md output urls.txt +memo.md diff --git a/README.md b/README.md index 7014ef0..ace1b28 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ [🌐 Website] • [🐱 GitHub] [🐦 Twitter] • - [🍀 Official Blog] + [🍀 Official Blog]
@@ -35,104 +35,146 @@ >このリポジトリのリリースノートやREADME、コミットメッセージの9割近くは[claude.ai](https://claude.ai/)や[ChatGPT4](https://chatgpt.com/)を活用した[AIRA](https://github.com/Sunwood-ai-labs/AIRA), [SourceSage](https://github.com/Sunwood-ai-labs/SourceSage), [Gaiah](https://github.com/Sunwood-ai-labs/Gaiah), [HarmonAI_II](https://github.com/Sunwood-ai-labs/HarmonAI_II)で生成しています。 -pegasus は、ウェブサイトを再帰的にクロールし、そのコンテンツを Markdown 形式に変換するパワフルで柔軟な Python パッケージです。指定した URL から始まり、リンクをたどって関連するページを探索し、HTML コンテンツを美しい Markdown ドキュメントに変換します。コマンドラインインターフェイス (CLI) から実行することも、Python スクリプトから直接使用することもできます。 +こんにちは!PEGASUSへようこそ!PEGASUSは、ウェブサイトを再帰的にクロールし、そのコンテンツを美しいMarkdown形式に変換するパワフルで柔軟なPythonパッケージです。 -## インストール +PEGASUSを使えば、指定したURLから始まり、リンクをたどって関連するページを探索し、HTMLコンテンツを見やすいMarkdownドキュメントに変換することができます。コマンドラインインターフェイス(CLI)から実行することも、Pythonスクリプトから直接使用することもできるので、とっても便利なんです! -pip を使用して pegasus をインストールします。 +## 🚀 インストール + +pipを使ってPEGASUSをインストールしましょう。以下のコマンドを実行するだけです!👇 ```shell pip install pegasus-surf ``` -## 使い方 +## 🎮 使い方 -### コマンドラインから +### 🖥️ コマンドラインから -pegasus をコマンドラインから使用するには、以下のようなコマンドを実行します。 +PEGASUSをコマンドラインから使用するには、以下のようなコマンドを実行します。 +#### 検索スクレイピング ```shell -pegasus https://example.com/start-page output_directory --exclude-selectors header footer nav --include-domain example.com --exclude-keywords login --output-extension txt +pegasus search --search-query "お好み焼き レシピ" +``` -pegasus --base-url https://docs.eraser.io/docs/what-is-eraser output/eraser_docs --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --include-domain docs.eraser.io --exclude-keywords login --output-extension .txt +#### 再帰スクレイピング -# 深度を指定して実行 -pegasus --base-url https://docs.eraser.io/docs/what-is-eraser output/eraser_docs2 --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --include-domain docs.eraser.io --exclude-keywords login --output-extension .txt --max-depth 2 +```shell +# 単一のURLからスクレイピングを開始 🌐 +pegasus recursive --base-url https://www.otafuku.co.jp/recipe/cook/noodle/nood01.html --output_dir output/yakisoba --exclude-selectors header footer nav --include-domain example.com --exclude-keywords login --output-extension .txt -# URLが記載されたテキストファイルを指定して実行 -pegasus --url-file urls.txt output/roomba --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --exclude-keywords login --output-extension .txt --max-depth 1 +# 探索深度を指定して実行 🔍 +pegasus recursive --base-url https://docs.eraser.io/docs/what-is-eraser --output_dir output/eraser_docs2 --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --include-domain docs.eraser.io --exclude-keywords login --output-extension .txt --max-depth 2 -# LLMを使った仕分け -pegasus --url-file urls.txt output/roomba2 --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --exclude-keywords login --output-extension .txt --max-depth 1 --system-message "あなたは、与えられたウェブサイトのコンテンツが特定のトピックに関連する有用な情報を含んでいるかどうかを判断するアシスタントです。トピックに関連する有益な情報が含まれている場合は「True」、そうでない場合は「False」と回答してください。" --classification-prompt "次のウェブサイトのコンテンツは、Roomba APIやiRobotに関する有益な情報を提供していますか? 提供している場合は「True」、そうでない場合は「False」と回答してください。" +# URLリストが記載されたテキストファイルからスクレイピングを開始 📜 +pegasus recursive --url-file urls.txt --output_dir output/okonomi --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --exclude-keywords login --output-extension .txt --max-depth 1 + +# LLMを使用したサイトの分類を行いながらスクレイピング 🧠 +pegasus recursive --url-file urls.txt --output_dir output/roomba2 --exclude-selectors header footer nav aside .sidebar .header .footer .navigation .breadcrumbs --exclude-keywords login --output-extension .txt --max-depth 1 --system-message "あなたは、与えられたウェブサイトのコンテンツが特定のトピックに関連する有用な情報を含んでいるかどうかを判断するアシスタントです。トピックに関連する有益な情報が含まれている場合は「True」、そうでない場合は「False」と回答してください。" --classification-prompt "次のウェブサイトのコンテンツは、Roomba APIやiRobotに関する有益な情報を提供していますか? 提供している場合は「True」、そうでない場合は「False」と回答してください。" ``` -- `https://example.com/start-page`: クロールを開始するベース URL を指定します。 -- `output_directory`: Markdown ファイルを保存するディレクトリを指定します。 -- `--exclude-selectors`: 除外する CSS セレクターをスペース区切りで指定します(オプション)。 -- `--include-domain`: クロールを特定のドメインに限定します(オプション)。 -- `--exclude-keywords`: URL に含まれる場合にページを除外するキーワードをスペース区切りで指定します(オプション)。 -- **`--output-extension`: 出力ファイルの拡張子を指定します(デフォルト: .md)。** -- **`--dust-size`: ダストフォルダに移動するファイルサイズのしきい値をバイト単位で指定します(デフォルト: 1000)。** -- **`--max-depth`: 再帰処理の最大深度を指定します(デフォルト: 制限なし)。** -- **`--url-file`: スクレイピングするURLが記載されたテキストファイルを指定します。** -- **`--system-message`: LLMのシステムメッセージを指定します(サイトの分類に使用)。** -- **`--classification-prompt`: LLMのサイト分類プロンプトを指定します。TrueまたはFalseを返すようにしてください。** +オプションの意味はこんな感じです!👀 + +- `--base-url`: スクレイピングを開始するベースURLを指定します。 +- `--url-file`: スクレイピングするURLが記載されたテキストファイルを指定します。 +- `--output-extension`: 出力ファイルの拡張子を指定します(デフォルト: .md)。 +- `--dust-size`: ダストフォルダに移動するファイルサイズのしきい値をバイト単位で指定します(デフォルト: 1000)。 +- `--max-depth`: 再帰処理の最大深度を指定します(デフォルト: 制限なし)。 +- `--system-message`: LLMのシステムメッセージを指定します(サイトの分類に使用)。 +- `--classification-prompt`: LLMのサイト分類プロンプトを指定します。TrueまたはFalseを返すようにしてください。 +- `--max-retries`: フィルタリングのリトライ回数の上限を指定します(デフォルト: 3)。 +- `--model`: LLMのモデル名を指定します(デフォルト: gemini/gemini-1.5-pro-latest)。 +- `--rate-limit-sleep`: レート制限エラー時のスリープ時間を秒単位で指定します(デフォルト: 60)。 +- `--other-error-sleep`: その他のエラー時のスリープ時間を秒単位で指定します(デフォルト: 10)。 -### Python スクリプトから +### 🐍 PythonスクリプトからPEGASUSを使う -pegasus を Python スクリプトから使用するには、以下のようなコードを書きます。 +PEGASUSをPythonスクリプトから使用するには、以下のようなコードを書きます。 ```python from pegasus import Pegasus pegasus = Pegasus( - base_url="https://example.com/start-page", output_dir="output_directory", exclude_selectors=['header', 'footer', 'nav'], include_domain="example.com", - exclude_keywords=["login"] + exclude_keywords=["login"], + output_extension=".txt", + dust_size=500, + max_depth=2, + system_message="You are an assistant to determine if the content of a given website contains useful information related to a specific topic. If it contains relevant and beneficial information about the topic, answer 'True', otherwise answer 'False'.", + classification_prompt="Does the content of the following website provide beneficial information about the Roomba API or iRobot? If so, answer 'True', if not, answer 'False'.", + max_retries=5, + model="gemini/gemini-1.5-pro-latest", + rate_limit_sleep=30, + other_error_sleep=5 ) -pegasus.run() +pegasus.run("https://example.com/start-page") ``` -- `base_url`: クロールを開始するベース URL を指定します。 -- `output_dir`: Markdown ファイルを保存するディレクトリを指定します。 -- `exclude_selectors`: 除外する CSS セレクターのリストを指定します(オプション)。 +パラメータの意味はこちらです! + +- `output_dir`: Markdownファイルを保存するディレクトリを指定します。 +- `exclude_selectors`: 除外するCSSセレクターのリストを指定します(オプション)。 - `include_domain`: クロールを特定のドメインに限定します(オプション)。 -- `exclude_keywords`: URL に含まれる場合にページを除外するキーワードのリストを指定します(オプション)。 -- **`output_extension`: 出力ファイルの拡張子を指定します(デフォルト: .md)。** -- **`dust_size`: ダストフォルダに移動するファイルサイズのしきい値をバイト単位で指定します(デフォルト: 1000)。** -- **`max_depth`: 再帰処理の最大深度を指定します(デフォルト: 制限なし)。** -- **`system_message`: LLMのシステムメッセージを指定します(サイトの分類に使用)。** -- **`classification_prompt`: LLMのサイト分類プロンプトを指定します。TrueまたはFalseを返すようにしてください。** +- `exclude_keywords`: URLに含まれる場合にページを除外するキーワードのリストを指定します(オプション)。 +- `output_extension`: 出力ファイルの拡張子を指定します(デフォルト: .md)。 +- `dust_size`: ダストフォルダに移動するファイルサイズのしきい値をバイト単位で指定します(デフォルト: 1000)。 +- `max_depth`: 再帰処理の最大深度を指定します(デフォルト: 制限なし)。 +- `system_message`: LLMのシステムメッセージを指定します(サイトの分類に使用)。 +- `classification_prompt`: LLMのサイト分類プロンプトを指定します。TrueまたはFalseを返すようにしてください。 +- `max_retries`: フィルタリングのリトライ回数の上限を指定します(デフォルト: 3)。 +- `model`: LLMのモデル名を指定します(デフォルト: gemini/gemini-1.5-pro-latest)。 +- `rate_limit_sleep`: レート制限エラー時のスリープ時間を秒単位で指定します(デフォルト: 60)。 +- `other_error_sleep`: その他のエラー時のスリープ時間を秒単位で指定します(デフォルト: 10)。 -## 特長 +## ✨ PEGASUSの特長 -- 指定した URL から始まり、リンクを再帰的にたどってウェブサイトを探索します。 -- HTML コンテンツを美しくフォーマットされた Markdown に変換します。 -- 柔軟な設定オプションにより、クロールと変換のプロセスをカスタマイズできます。 -- ヘッダー、フッター、ナビゲーションなどの不要な要素を除外できます。 -- 特定のドメインのみをクロールするように制限できます。 -- 特定のキーワードを含む URL を除外できます。 -- **URLリストを記載したテキストファイルを指定してスクレイピングできます。** -- **LLMを使ってスクレイピングしたサイトを分類できます。** +- 指定したURLから始まり、リンクを再帰的にたどってウェブサイトを探索します。🔍 +- HTMLコンテンツを美しくフォーマットされたMarkdownに変換します。📝 +- 柔軟な設定オプションにより、クロールと変換のプロセスをカスタマイズできます。⚙️ +- ヘッダー、フッター、ナビゲーションなどの不要な要素を除外できます。🙅♀️ +- 特定のドメインのみをクロールするように制限できます。🌐 +- 特定のキーワードを含むURLを除外できます。🚫 +- URLリストを記載したテキストファイルを指定してスクレイピングできます。📜 +- LLMを使ってスクレイピングしたサイトを分類できます。🧠 -## 注意事項 +## ⚠️ 注意事項 -- pegasus は、適切な使用方法とウェブサイトの利用規約に従ってご利用ください。 -- 過度なリクエストを送信しないよう、適切な遅延を設けてください。 +- PEGASUSは、適切な使用方法とウェブサイトの利用規約に従ってご利用ください。🙏 +- 過度なリクエストを送信しないよう、適切な遅延を設けてください。⏰ -## ライセンス +## 📜 ライセンス -このプロジェクトは MIT ライセンスの下で公開されています。詳細については、[LICENSE](LICENSE) ファイルを参照してください。 +このプロジェクトはMITライセンスの下で公開されています。詳細については、[LICENSE](LICENSE)ファイルを参照してください。 -## 貢献 +## 開発者用 -プルリクエストや改善案は大歓迎です。バグ報告や機能リクエストがある場合は、issue を作成してください。 +### パッケージの構成 ---- +[View on Eraser](https://app.eraser.io/workspace/8cnaevNcF1kxMsfSfGl0?elements=ooYqYlIqai8z1hvLott86w) + +### パッケージのフローチャート -pegasus を使用すれば、ウェブサイトを再帰的に探索し、コンテンツを美しい Markdown ドキュメントに変換できます。ドキュメンテーションの自動化、コンテンツの管理、データ分析などにぜひお役立てください! + + +### パッケージのER図 + +[View on Eraser](https://app.eraser.io/workspace/8cnaevNcF1kxMsfSfGl0?elements=KStkmTRUuZ5AiJNPC8E40g) + +### SourceSage + +```shell +sourcesage --mode DocuMind --docuMind-model "gemini/gemini-1.5-pro-latest" --docuMind-db ".SourceSageAssets\DOCUMIND\Repository_summary.md" --docuMind-release-report ".SourceSageAssets\RELEASE_REPORT\Report_v0.3.0.md" --docuMind-changelog ".SourceSageAssets\Changelog\CHANGELOG_release_5.0.0.md" --docuMind-output ".SourceSageAssets/DOCUMIND/RELEASE_NOTES_v0.3.0.md" --docuMind-prompt-output ".SourceSageAssets/DOCUMIND/_PROMPT_v0.3.0.md" --repo-name "SourceSage" --repo-version "v0.3.0" ``` -以上がREADMEの修正案です。リポジトリの更新内容を反映し、LLMを使ったサイト分類機能や新しいオプションについて説明を追加しました。使用例も拡充して、ツールの活用方法がより明確になるようにしています。 \ No newline at end of file +## 🤝 貢献 + +プルリクエストや改善案は大歓迎です!🎉 バグ報告や機能リクエストがある場合は、issueを作成してください。😊 + +--- + +PEGASUSを使用すれば、ウェブサイトを再帰的に探索し、コンテンツを美しいMarkdownドキュメントに変換できます。📜✨ ドキュメンテーションの自動化、コンテンツの管理、データ分析などにぜひお役立てください!🙌 \ No newline at end of file diff --git a/example/ex06_ddg_recipe_query.py b/example/ex06_ddg_recipe_query.py new file mode 100644 index 0000000..67f334e --- /dev/null +++ b/example/ex06_ddg_recipe_query.py @@ -0,0 +1,21 @@ +from duckduckgo_search import DDGS +import json + +# クエリ +with DDGS() as ddgs: + results = list(ddgs.text( + keywords='お好み焼き レシピ', # 検索ワード + region='jp-jp', # リージョン 日本は"jp-jp",指定なしの場合は"wt-wt" + safesearch='off', # セーフサーチOFF->"off",ON->"on",標準->"moderate" + timelimit=None, # 期間指定 指定なし->None,過去1日->"d",過去1週間->"w", + # 過去1か月->"m",過去1年->"y" + max_results=4 # 取得件数 + )) + +# レスポンスの表示 +for line in results: + print(json.dumps( + line, + indent=2, + ensure_ascii=False + )) \ No newline at end of file diff --git a/pegasus/Pegasus.py b/pegasus/Pegasus.py index 8d2a816..72d9488 100644 --- a/pegasus/Pegasus.py +++ b/pegasus/Pegasus.py @@ -10,14 +10,15 @@ from litellm import completion from tqdm import tqdm import litellm -# litellm.set_verbose=True +from duckduckgo_search import DDGS +import json logger = loguru.logger class Pegasus: def __init__(self, output_dir, exclude_selectors=None, include_domain=None, exclude_keywords=None, output_extension=".md", dust_size=1000, max_depth=None, system_message=None, classification_prompt=None, max_retries=3, - model='gemini/gemini-1.5-pro-latest', rate_limit_sleep=60, other_error_sleep=10): + model='gemini/gemini-1.5-pro-latest', rate_limit_sleep=60, other_error_sleep=10, search_query=None, max_results=10, base_url=None, url_file="urls.txt"): self.output_dir = output_dir self.exclude_selectors = exclude_selectors self.include_domain = include_domain @@ -33,6 +34,10 @@ def __init__(self, output_dir, exclude_selectors=None, include_domain=None, excl self.model = model self.rate_limit_sleep = rate_limit_sleep self.other_error_sleep = other_error_sleep + self.search_query = search_query + self.max_results = max_results + self.base_url = base_url + self.url_file = url_file tprint(" Pegasus ", font="rnd-xlarge") logger.info("初期化パラメータ:") logger.info(f" output_dir: {output_dir}") @@ -48,6 +53,34 @@ def __init__(self, output_dir, exclude_selectors=None, include_domain=None, excl logger.info(f" model: {model}") logger.info(f" rate_limit_sleep: {rate_limit_sleep}") logger.info(f" other_error_sleep: {other_error_sleep}") + logger.info(f" search_query: {search_query}") + logger.info(f" max_results: {max_results}") + logger.info(f" base_url: {base_url}") + logger.info(f" url_file: {url_file}") + + + def search_scraping(self): + tprint(">> Search Scraping ") + if self.search_query is None: + return + + with DDGS() as ddgs: + results = list(ddgs.text( + keywords=self.search_query, + region='jp-jp', + safesearch='off', + timelimit=None, + max_results=self.max_results + )) + + with open("urls.txt", "w", encoding="utf-8") as file: + for result in results: + url = result['href'] + title = result['title'] + body = result['body'] + file.write(f"{url}, {title}, {body[:20]}\n") + + logger.info(f"検索スクレイピング完了 .... {self.max_results}件取得") def filter_site(self, markdown_content): if(self.classification_prompt is None): @@ -61,7 +94,7 @@ def filter_site(self, markdown_content): {"role": "user", "content": f"{self.classification_prompt}\n\n{markdown_content}"} ] response = completion( - model="gemini/gemini-1.5-pro-latest", + model=self.model, messages=messages ) content = response.get('choices', [{}])[0].get('message', {}).get('content') @@ -77,9 +110,9 @@ def filter_site(self, markdown_content): logger.warning(f"フィルタリングでエラーが発生しました。リトライします。({retry_count}/{self.max_retries})\nError: {e}") if "429" in str(e): - sleep_time = self.rate_limit_sleep # レート制限エラー時のスリープ時間をself.rate_limit_sleepから取得 + sleep_time = self.rate_limit_sleep else: - sleep_time = self.other_error_sleep # その他のエラー時のスリープ時間をself.other_error_sleepから取得 + sleep_time = self.other_error_sleep for _ in tqdm(range(sleep_time), desc="Sleeping", unit="s"): time.sleep(1) @@ -87,7 +120,7 @@ def filter_site(self, markdown_content): logger.error(f"フィルタリングに失敗しました。リトライ回数の上限に達しました。({self.max_retries}回)") return True - def download_and_convert(self, url, depth=0): + def download_and_convert(self, url, title, depth=0): if url in self.visited_urls: return self.visited_urls.add(url) @@ -106,6 +139,11 @@ def download_and_convert(self, url, depth=0): markdown_content = markdownify.markdownify(str(soup)) markdown_content = re.sub(r'\n{5,}', '\n\n\n\n', markdown_content) + # 文字化けチェック + if not self.is_valid_text(markdown_content): + logger.warning(f"文字化けを検出したため除外: {url}") + return + if not self.filter_site(markdown_content): parsed_url = urlparse(url) domain = parsed_url.netloc @@ -130,7 +168,7 @@ def download_and_convert(self, url, depth=0): with open(output_file, 'w', encoding='utf-8') as file: file.write(markdown_content) - logger.info(f"[{depth}]変換成功: {url} ---> {output_file} [{len(markdown_content)/1000}kb]") + logger.info(f"[Depth:{depth}]変換成功: {url} ---> {output_file} [{len(markdown_content)/1000}kb]") if domain not in self.domain_summaries: self.domain_summaries[domain] = [] @@ -148,13 +186,24 @@ def download_and_convert(self, url, depth=0): if any(keyword in absolute_url for keyword in self.exclude_keywords): continue absolute_url = absolute_url.split('#')[0] - self.download_and_convert(absolute_url, depth + 1) + self.download_and_convert(absolute_url, title, depth + 1) except requests.exceptions.RequestException as e: logger.error(f"ダウンロードエラー: {url}: {e}") except IOError as e: logger.error(f"書き込みエラー: {output_file}: {e}") + def is_valid_text(self, text): + # ASCII範囲外の文字の割合を計算 + non_ascii_chars = re.findall(r'[^\x00-\x7F]', text) + non_ascii_ratio = len(non_ascii_chars) / len(text) + + # 割合が一定以上であれば文字化けとみなす + if non_ascii_ratio > 0.3: + return False + else: + return True + def create_domain_summaries(self): for domain, summaries in self.domain_summaries.items(): summary_file = os.path.join(self.output_dir, f"{domain}_summary{self.output_extension}") @@ -162,8 +211,21 @@ def create_domain_summaries(self): file.write('\n\n'.join(summaries)) logger.info(f"サマリーファイル作成: {summary_file}") - def run(self, base_url): - logger.info(f"スクレイピング開始: base_url={base_url}") - self.download_and_convert(base_url) + def recursive_scraping(self): + tprint(">> Recursive Scraping ") + logger.info("再帰スクレイピング開始") + if self.base_url: + logger.info(f"base_url={self.base_url} から再帰スクレイピングを開始します") + self.download_and_convert(self.base_url, "") + else: + with open("urls.txt", "r", encoding="utf-8") as file: + for line in file: + parts = line.strip().split(",") + url = parts[0] + title = parts[1] if len(parts) > 1 else "" + logger.info(f"---------------------------------------") + logger.info(f"スクレイピング開始: url={url}") + if(title): logger.info(f"タイトル: {title})") + self.download_and_convert(url, title) self.create_domain_summaries() - logger.info("スクレイピング完了") \ No newline at end of file + logger.info("再帰スクレイピング完了") \ No newline at end of file diff --git a/pegasus/cli.py b/pegasus/cli.py index 3967257..cf1e398 100644 --- a/pegasus/cli.py +++ b/pegasus/cli.py @@ -5,9 +5,8 @@ def main(): parser = argparse.ArgumentParser(description='Pegasus') - parser.add_argument('--base-url', help='スクレイピングを開始するベースURL') - parser.add_argument('--url-file', help='スクレイピングするURLが記載されたテキストファイル') - parser.add_argument('output_dir', help='Markdownファイルの出力ディレクトリ') + parser.add_argument('mode', choices=['search', 'recursive'], help='実行モード(検索スクレイピングまたは再帰スクレイピング)') + parser.add_argument('--output_dir', default='output', help='Markdownファイルの出力ディレクトリ') parser.add_argument('--exclude-selectors', nargs='+', help='除外するCSSセレクター') parser.add_argument('--include-domain', default='', help='URLマッチングに含めるドメイン') parser.add_argument('--exclude-keywords', nargs='+', help='URLマッチングから除外するキーワード') @@ -20,7 +19,11 @@ def main(): parser.add_argument('--model', default='gemini/gemini-1.5-pro-latest', help='LiteLLMのモデル名 (デフォルト: gemini/gemini-1.5-pro-latest)') parser.add_argument('--rate-limit-sleep', type=int, default=60, help='レート制限エラー時のスリープ時間(秒) (デフォルト: 60)') parser.add_argument('--other-error-sleep', type=int, default=10, help='その他のエラー時のスリープ時間(秒) (デフォルト: 10)') - + parser.add_argument('--search-query', help='検索スクレイピングで使用するクエリ') + parser.add_argument('--max-results', type=int, default=3, help='検索スクレイピングの最大数') + parser.add_argument('--base-url', help='再帰スクレイピングを開始するベースURL') + parser.add_argument('--url-file', default="urls.txt", help='スクレイピングするURLが記載されたテキストファイル') + args = parser.parse_args() pegasus = Pegasus( @@ -33,18 +36,20 @@ def main(): max_depth=args.max_depth, system_message=args.system_message, classification_prompt=args.classification_prompt, - max_retries=args.max_retries + max_retries=args.max_retries, + model=args.model, + rate_limit_sleep=args.rate_limit_sleep, + other_error_sleep=args.other_error_sleep, + search_query=args.search_query, + max_results=args.max_results, + base_url=args.base_url, + url_file=args.url_file ) - if args.base_url: - pegasus.run(args.base_url) - elif args.url_file: - with open(args.url_file, 'r') as file: - urls = file.read().splitlines() - for url in urls: - pegasus.run(url) - else: - parser.error("--base-url または --url-file のいずれかを指定してください。") + if args.mode == 'search': + pegasus.search_scraping() + elif args.mode == 'recursive': + pegasus.recursive_scraping() if __name__ == '__main__': main() \ No newline at end of file diff --git a/setup.py b/setup.py index ad575cb..14210c2 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='pegasus-surf', - version='0.2.0', + version='0.2.4', description='A package for scraping websites and converting them to Markdown', author='Maki', author_email='sunwood.ai.labs@gmail.com', @@ -23,6 +23,7 @@ 'litellm', 'python-dotenv', 'google-generativeai', + 'duckduckgo-search', ], entry_points={ 'console_scripts': [