syurein commited on
Commit
68c46ce
·
1 Parent(s): fed06ef

search機能の実装

Browse files
__pycache__/LLM_package.cpython-312.pyc CHANGED
Binary files a/__pycache__/LLM_package.cpython-312.pyc and b/__pycache__/LLM_package.cpython-312.pyc differ
 
__pycache__/search.cpython-312.pyc CHANGED
Binary files a/__pycache__/search.cpython-312.pyc and b/__pycache__/search.cpython-312.pyc differ
 
app.py CHANGED
@@ -69,6 +69,8 @@ import numpy as np
69
  from datetime import datetime
70
  from ultralytics import YOLO
71
  from PIL import Image
 
 
72
  app = FastAPI()
73
  # CORSミドルウェアの追加
74
  app.add_middleware(
@@ -229,6 +231,25 @@ def create_mask(image, x1, y1, x2, y2):
229
 
230
 
231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  def llm_to_process_image_simple(risk_level, image_path, point1, point2, thresholds=None):
233
  print(risk_level, image_path, point1, point2, thresholds)
234
  print('point1,point2', point1, point2)
@@ -262,8 +283,8 @@ def llm_to_process_image_simple(risk_level, image_path, point1, point2, threshol
262
  return save_dir + debug_image_path
263
 
264
 
265
-
266
- def llm_to_process_image_simple_auto(risk_level, image_path, point1, point2, thresholds=None):
267
  print(risk_level, image_path, point1, point2, thresholds)
268
  print('point1,point2', point1, point2)
269
  GEMINI_API_KEY=os.getenv('GEMINI_API_KEY')
@@ -273,6 +294,13 @@ def llm_to_process_image_simple_auto(risk_level, image_path, point1, point2, thr
273
  response=Objectdetector.detect_auto(image_path)
274
  print(response["objects_to_remove"])
275
  Objectdetector.prompt_objects=response["objects_to_remove"]
 
 
 
 
 
 
 
276
  # 画像の読み込みとRGB変換
277
  print(f"Objectdetector.prompt_objects: {Objectdetector.prompt_objects}")
278
  image = cv2.imread(image_path)
@@ -1010,13 +1038,6 @@ async def create_mask_sum_auto(image: UploadFile = File(...), risk_level: int =
1010
 
1011
 
1012
 
1013
-
1014
-
1015
-
1016
-
1017
-
1018
-
1019
-
1020
  # カスケードファイルの読み込み (顔検出)
1021
  #face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
1022
 
 
69
  from datetime import datetime
70
  from ultralytics import YOLO
71
  from PIL import Image
72
+ from search import WebScraper
73
+
74
  app = FastAPI()
75
  # CORSミドルウェアの追加
76
  app.add_middleware(
 
231
 
232
 
233
 
234
+ async def search_llm():
235
+ scraper = WebScraper(headless=True) # UIなしで実行
236
+
237
+ # 個人情報流出に関する事例を検索し、上位2件のクリーンなコンテンツを取得
238
+ personal_breach_docs = await scraper.get_processed_documents(
239
+ search_query="個人情報流出 事例 SNS",
240
+ num_search_results=10
241
+ )
242
+ return personal_breach_docs["cleaned_html_content"]
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
  def llm_to_process_image_simple(risk_level, image_path, point1, point2, thresholds=None):
254
  print(risk_level, image_path, point1, point2, thresholds)
255
  print('point1,point2', point1, point2)
 
283
  return save_dir + debug_image_path
284
 
285
 
286
+ import asyncio
287
+ async def llm_to_process_image_simple_auto(risk_level, image_path, point1, point2, thresholds=None):
288
  print(risk_level, image_path, point1, point2, thresholds)
289
  print('point1,point2', point1, point2)
290
  GEMINI_API_KEY=os.getenv('GEMINI_API_KEY')
 
294
  response=Objectdetector.detect_auto(image_path)
295
  print(response["objects_to_remove"])
296
  Objectdetector.prompt_objects=response["objects_to_remove"]
297
+ # 個人情報流出に関する事例を検索し、上位2件のクリーンなコンテンツを取得
298
+ scraper = WebScraper(headless=True)
299
+ personal_breach_docs = asyncio.run(await scraper.get_processed_documents(
300
+ search_query="個人情報流出 事例 SNS",
301
+ num_search_results=10
302
+ ))
303
+ Objectdetector.text=personal_breach_docs["cleaned_html_content"]
304
  # 画像の読み込みとRGB変換
305
  print(f"Objectdetector.prompt_objects: {Objectdetector.prompt_objects}")
306
  image = cv2.imread(image_path)
 
1038
 
1039
 
1040
 
 
 
 
 
 
 
 
1041
  # カスケードファイルの読み込み (顔検出)
1042
  #face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
1043
 
requirements.txt CHANGED
@@ -73,4 +73,4 @@ supervision
73
  onnxruntime
74
  google-genai
75
  python-dotenv
76
- # moondream # ここを削除
 
73
  onnxruntime
74
  google-genai
75
  python-dotenv
76
+
search.py CHANGED
@@ -1,7 +1,7 @@
1
  import asyncio
2
- from playwright.async_api import async_playwright, Page, Browser
3
  from bs4 import BeautifulSoup
4
- from bs4.element import Comment # BeautifulSoupのコメント削除用
5
  from urllib.parse import urlparse, parse_qs
6
  from typing import List, Dict, Optional
7
 
@@ -19,23 +19,31 @@ class WebScraper:
19
  """
20
  self.headless = headless
21
  self.default_timeout = default_timeout
22
- self._browser: Optional[Browser] = None # Browserインスタンスを保持するため
 
23
 
24
  async def _launch_browser(self) -> Browser:
25
- """ブラウザを起動し、インスタンス変数に格納します。"""
 
 
26
  if not self._browser or not self._browser.is_connected():
27
- self._browser = await async_playwright().chromium.launch(headless=self.headless)
 
 
28
  return self._browser
29
 
30
  async def _close_browser(self):
31
- """ブラウザを閉じます。"""
32
  if self._browser and self._browser.is_connected():
33
  await self._browser.close()
34
  self._browser = None
 
 
 
35
 
36
  async def _get_new_page(self) -> Page:
37
  """新しいページ(タブ)を作成します。"""
38
- browser = await self._launch_browser()
39
  page = await browser.new_page()
40
  page.set_default_timeout(self.default_timeout)
41
  return page
@@ -45,37 +53,50 @@ class WebScraper:
45
  DuckDuckGoで指定されたクエリを検索し、上位N件の検索結果(タイトルとURL)を返します。
46
  """
47
  results = []
48
- page: Optional[Page] = None # 明示的に型ヒントを追加
 
49
  try:
50
  page = await self._get_new_page()
 
 
 
 
 
 
 
51
  print(f"DuckDuckGoで '{query}' を検索中...")
52
- await page.goto("https://duckduckgo.com/")
 
53
 
54
- await page.fill("#search_form_input_homepage", query)
55
- await page.press("#search_form_input_homepage", "Enter")
 
 
56
 
57
- await page.wait_for_selector("#links .result__a", timeout=10000)
 
58
 
59
- search_elements = await page.query_selector_all("#links .result")
60
-
61
- for i, element in enumerate(search_elements):
62
- if i >= num_results:
63
- break
64
 
65
- title_element = await element.query_selector(".result__a")
66
- url_element = await element.query_selector(".result__url")
67
-
68
- title = await title_element.text_content() if title_element else "タイトルなし"
69
- url = await url_element.get_attribute("href") if url_element else "URLなし"
70
 
71
- # DuckDuckGoURLのデコードとクリーンアップ
72
- if url and url != "URLなし":
73
  parsed_url = urlparse(url)
74
- if parsed_url.path == '/l/':
 
75
  decoded_url = parse_qs(parsed_url.query).get('uddg', [''])[0]
76
  url = decoded_url
77
 
78
- results.append({"title": title.strip(), "url": url.strip()})
 
 
 
79
  except Exception as e:
80
  print(f"DuckDuckGo検索中にエラーが発生しました: {e}")
81
  finally:
@@ -91,7 +112,8 @@ class WebScraper:
91
  try:
92
  page = await self._get_new_page()
93
  print(f" URL: {url} のコンテンツを取得中...")
94
- await page.goto(url)
 
95
  return await page.content()
96
  except Exception as e:
97
  print(f" URL: {url} のコンテンツ取得中にエラーが発生しました: {e}")
@@ -121,6 +143,7 @@ class WebScraper:
121
 
122
  # 複数の連続する改行を1つに減らす
123
  cleaned_text = soup.get_text(separator='\n', strip=True)
 
124
  cleaned_text_lines = [line.strip() for line in cleaned_text.splitlines() if line.strip()]
125
  return '\n'.join(cleaned_text_lines)
126
 
@@ -138,11 +161,8 @@ class WebScraper:
138
  """
139
  processed_documents = []
140
 
141
- # Playwrightの非同期コンテキストマネージャでブラウザインスタンスを管理
142
- async with async_playwright() as p:
143
- # ブラウザを一度だけ起動し、インスタンス変数に保持
144
- self._browser = await p.chromium.launch(headless=self.headless)
145
-
146
  top_results = await self.search_duckduckgo(search_query, num_search_results)
147
 
148
  if top_results:
@@ -167,9 +187,27 @@ class WebScraper:
167
  print(" クリーンなコンテンツを取得できませんでした。")
168
  else:
169
  print("検索結果が見つからなかったため、処理をスキップします。")
170
-
171
- await self._close_browser() # 全ての処理後にブラウザを閉じる
 
172
 
173
  return processed_documents
174
 
175
  # クラスの使用例
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
+ from playwright.async_api import async_playwright, Page, Browser, Playwright
3
  from bs4 import BeautifulSoup
4
+ from bs4.element import Comment
5
  from urllib.parse import urlparse, parse_qs
6
  from typing import List, Dict, Optional
7
 
 
19
  """
20
  self.headless = headless
21
  self.default_timeout = default_timeout
22
+ self._browser: Optional[Browser] = None
23
+ self._playwright_instance: Optional[Playwright] = None # Playwrightインスタンスを保持
24
 
25
  async def _launch_browser(self) -> Browser:
26
+ """Playwrightを起動し、ブラウザを立ち上げます。
27
+ 既にブラウザが起動していればそれを再利用します。
28
+ """
29
  if not self._browser or not self._browser.is_connected():
30
+ if self._playwright_instance is None:
31
+ self._playwright_instance = await async_playwright().start()
32
+ self._browser = await self._playwright_instance.chromium.launch(headless=self.headless)
33
  return self._browser
34
 
35
  async def _close_browser(self):
36
+ """ブラウザを閉じ、Playwrightインスタンスも停止します。"""
37
  if self._browser and self._browser.is_connected():
38
  await self._browser.close()
39
  self._browser = None
40
+ if self._playwright_instance:
41
+ await self._playwright_instance.stop()
42
+ self._playwright_instance = None
43
 
44
  async def _get_new_page(self) -> Page:
45
  """新しいページ(タブ)を作成します。"""
46
+ browser = await self._launch_browser() # ブラウザが起動または取得される
47
  page = await browser.new_page()
48
  page.set_default_timeout(self.default_timeout)
49
  return page
 
53
  DuckDuckGoで指定されたクエリを検索し、上位N件の検索結果(タイトルとURL)を返します。
54
  """
55
  results = []
56
+ page: Optional[Page] = None
57
+
58
  try:
59
  page = await self._get_new_page()
60
+ """Playwrightのステルス技術を適用し、ボット検出を回避します。"""
61
+ await page.evaluate("""Object.defineProperty(navigator, 'webdriver', { get: () => false });""")
62
+ await page.evaluate("""Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });""")
63
+ await page.evaluate("""Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });""")
64
+ await page.evaluate("""window.chrome = { runtime: {}, loadTimes: function() {}, csi: function() {}, app: {} };""")
65
+ await page.evaluate("""Object.defineProperty(navigator.permissions, 'query', { enumerable: true, configurable: true, writable: true, value: async (parameters) => ({ state: 'prompt' }) });""")
66
+
67
  print(f"DuckDuckGoで '{query}' を検索中...")
68
+ # DuckDuckGoの検索URLは一般的に `?q=` パラメータを使用します
69
+ await page.goto(f"https://duckduckgo.com/?q={query}")
70
 
71
+ # 検索結果のタイトルリンク要素を特定するセレクタ
72
+ # DuckDuckGoのHTML構造は変更される可能性があるため、適宜調整が必要
73
+ # 現在の一般的なセレクタは 'a[data-testid="result-title-link"]'
74
+ await page.wait_for_selector('h2 > a', timeout=10000)
75
 
76
+ # 検索結果のタイトルリンク要素を取得 (await は不要、Locatorオブジェクトを返す)
77
+ search_links = page.locator('h2 > a')
78
 
79
+ # 取得する結果の数を制限
80
+ for i in range(min(num_results, await search_links.count())):
81
+ link_element = search_links.nth(i)
 
 
82
 
83
+ # タイトルはリンク要素のテキストコンテンツ
84
+ title = await link_element.text_content()
85
+ # URLはリンク要素のhref属性
86
+ url = await link_element.get_attribute("href")
 
87
 
88
+ # DuckDuckGoのリダイレクトURLのデコードとクリーンアップ
89
+ if url:
90
  parsed_url = urlparse(url)
91
+ # DuckDuckGoのリダイレクトURLかどうかをチェック
92
+ if parsed_url.netloc == 'duckduckgo.com' and parsed_url.path == '/l/':
93
  decoded_url = parse_qs(parsed_url.query).get('uddg', [''])[0]
94
  url = decoded_url
95
 
96
+ # 結果を追加する前に、タイトルとURLが有効か軽くチェック
97
+ if title and url and title.strip() != "" and url.strip() != "":
98
+ results.append({"title": title.strip(), "url": url.strip()})
99
+
100
  except Exception as e:
101
  print(f"DuckDuckGo検索中にエラーが発生しました: {e}")
102
  finally:
 
112
  try:
113
  page = await self._get_new_page()
114
  print(f" URL: {url} のコンテンツを取得中...")
115
+ # 'domcontentloaded' は 'load' よりも高速な場合が多い
116
+ await page.goto(url, wait_until='domcontentloaded')
117
  return await page.content()
118
  except Exception as e:
119
  print(f" URL: {url} のコンテンツ取得中にエラーが発生しました: {e}")
 
143
 
144
  # 複数の連続する改行を1つに減らす
145
  cleaned_text = soup.get_text(separator='\n', strip=True)
146
+ # 空行を削除し、各行をトリム
147
  cleaned_text_lines = [line.strip() for line in cleaned_text.splitlines() if line.strip()]
148
  return '\n'.join(cleaned_text_lines)
149
 
 
161
  """
162
  processed_documents = []
163
 
164
+ # クラスのインスタンスでブラウザのライフサイクルを管理
165
+ try:
 
 
 
166
  top_results = await self.search_duckduckgo(search_query, num_search_results)
167
 
168
  if top_results:
 
187
  print(" クリーンなコンテンツを取得できませんでした。")
188
  else:
189
  print("検索結果が見つからなかったため、処理をスキップします。")
190
+ finally:
191
+ # すべての処理が完了したらブラウザを閉じる
192
+ await self._close_browser()
193
 
194
  return processed_documents
195
 
196
  # クラスの使用例
197
+ async def main():
198
+ scraper = WebScraper(headless=False) # デバッグのためにheadless=Falseにしても良い
199
+ query = "個人情報流出 事例"
200
+ documents = await scraper.get_processed_documents(query, num_search_results=2)
201
+
202
+ if documents:
203
+ print("\n--- 処理されたドキュメント ---")
204
+ for doc in documents:
205
+ print(f"タイトル: {doc['title']}")
206
+ print(f"URL: {doc['original_url']}")
207
+ # print(f"コンテンツの長さ: {len(doc['cleaned_html_content'])} 文字")
208
+ # print(f"コンテンツの一部: {doc['cleaned_html_content'][:200]}...\n")
209
+ else:
210
+ print("処理されたドキュメントはありませんでした。")
211
+
212
+ if __name__ == "__main__":
213
+ asyncio.run(main())
test.py CHANGED
@@ -3,11 +3,13 @@ import os
3
  from dotenv import load_dotenv
4
  import numpy as np
5
  import cv2
 
 
6
  from PIL import Image
7
  from search import WebScraper
8
  load_dotenv(dotenv_path='../.env')
9
  async def main():
10
- scraper = WebScraper(headless=True) # UIなしで実行
11
 
12
  # 個人情報流出に関する事例を検索し、上位2件のクリーンなコンテンツを取得
13
  personal_breach_docs = await scraper.get_processed_documents(
@@ -24,4 +26,5 @@ async def main():
24
  print("-" * 30)
25
  else:
26
  print("処理されたドキュメントはありませんでした。")
27
- main()
 
 
3
  from dotenv import load_dotenv
4
  import numpy as np
5
  import cv2
6
+ import asyncio
7
+
8
  from PIL import Image
9
  from search import WebScraper
10
  load_dotenv(dotenv_path='../.env')
11
  async def main():
12
+ scraper = WebScraper(headless=False) # UIなしで実行
13
 
14
  # 個人情報流出に関する事例を検索し、上位2件のクリーンなコンテンツを取得
15
  personal_breach_docs = await scraper.get_processed_documents(
 
26
  print("-" * 30)
27
  else:
28
  print("処理されたドキュメントはありませんでした。")
29
+ if __name__ == "__main__":
30
+ asyncio.run(main())