Update playwright/README.md
This commit is contained in:
@@ -1,157 +1,101 @@
|
|||||||
```python
|
```python
|
||||||
# google.py
|
# %%
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from textwrap import wrap
|
||||||
|
import re
|
||||||
|
|
||||||
#%%
|
async def summarize_page(page):
|
||||||
import xvfbwrapper, playwright.async_api
|
content = await page.content()
|
||||||
from PIL import Image; from io import *
|
soup = BeautifulSoup(content, 'html.parser')
|
||||||
#%%
|
|
||||||
xvfbwrapper.Xvfb().start()
|
|
||||||
playwright = await playwright.async_api.async_playwright().start()
|
|
||||||
browser = await playwright.chromium.launch(headless=False,
|
|
||||||
args=['--enable-features=WebContentsForceDark'])
|
|
||||||
page = await browser.new_page()
|
|
||||||
#%%
|
|
||||||
await page.goto('https://google.com')
|
|
||||||
image = Image.open(BytesIO(await page.screenshot()))
|
|
||||||
image.save('google.png')
|
|
||||||
```
|
|
||||||
|
|
||||||
위의 `google.py`는 top-level await를 사용하므로 아래와 같이 실행해야 한다.
|
print(f"\n{'=' * 50}\n{soup.title.string or 'No title'}\n{'=' * 50}\n")
|
||||||
```sh
|
|
||||||
python -m asyncio < google.py
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
main_content = soup.body
|
||||||
# play.py
|
if main_content:
|
||||||
from playwright.async_api import async_playwright as aP
|
texts = main_content.find_all(string=True)
|
||||||
import os, io, asyncio, xvfbwrapper
|
|
||||||
from db import DB
|
|
||||||
|
|
||||||
async def Page(browser='chromium', headless=True):
|
def clean_text(text):
|
||||||
if headless: xvfbwrapper.Xvfb().start()
|
text = re.sub(r'\s+', ' ', text)
|
||||||
else: os.environ['DISPLAY'] = ':0'
|
text = re.sub(r'\.{2,}', '.', text)
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
db = DB()
|
visible_texts = [clean_text(t) for t in texts
|
||||||
playwright = await aP().start()
|
if t.parent.name not in ['style', 'script', 'head', 'title', 'meta', '[document]']]
|
||||||
browser = await getattr(playwright, browser).launch(headless=False)
|
visible_texts = [t for t in visible_texts if t]
|
||||||
context = await browser.new_context(accept_downloads=True)
|
|
||||||
context.set_default_timeout(0)
|
|
||||||
|
|
||||||
async def save(response):
|
if visible_texts:
|
||||||
try:
|
print(f"{visible_texts.pop(0)}\n")
|
||||||
if response.ok and not db.exists(url := response.url):
|
|
||||||
db[url] = await response.body()
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
async def load(route):
|
summary = ' '.join(visible_texts)
|
||||||
if body := db[route.request.url]: return await route.fulfill(body=body)
|
summary = re.sub(r'\s*\.\s*', '. ', summary)
|
||||||
await route.continue_()
|
summary = ' '.join(summary.split()[:100])
|
||||||
|
print('\n'.join(wrap(summary, width=80)))
|
||||||
|
|
||||||
context.on('response', save)
|
print("\n" + "-" * 50 + "\n")
|
||||||
await context.route('**/*', load)
|
|
||||||
for block in ['**/*.gif', '**/css*.js']:
|
|
||||||
await context.route(block, lambda route: route.abort())
|
|
||||||
|
|
||||||
return await context.new_page()
|
seen = set()
|
||||||
|
for selector in ['input', 'button', 'textarea', 'select']:
|
||||||
|
elements = await page.query_selector_all(selector)
|
||||||
|
for element in elements:
|
||||||
|
if await element.is_visible():
|
||||||
|
async def get_element_info(element):
|
||||||
|
props = ['id', 'name', 'type', 'value', 'placeholder', 'aria-label', 'role']
|
||||||
|
info = {}
|
||||||
|
for prop in props:
|
||||||
|
value = await element.get_attribute(prop)
|
||||||
|
if value:
|
||||||
|
info[prop] = value
|
||||||
|
|
||||||
|
tag_name = await element.evaluate('el => el.tagName.toLowerCase()')
|
||||||
|
info['tag'] = tag_name
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
element_info = await get_element_info(element)
|
||||||
|
tag = element_info.pop('tag', 'unknown')
|
||||||
|
|
||||||
|
attrs = ' '.join([f'{k}="{v}"' for k, v in element_info.items()])
|
||||||
|
element_str = f"<{tag} {attrs}>"
|
||||||
|
|
||||||
|
if element_str not in seen:
|
||||||
|
print(element_str)
|
||||||
|
seen.add(element_str)
|
||||||
|
|
||||||
|
print("\n" + "-" * 50 + "\n")
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
page = await Page()
|
async with async_playwright() as p:
|
||||||
await page.goto('https://reddit.com')
|
browser = await p.firefox.launch()
|
||||||
await page.screenshot(path='screenshot.png')
|
page = await browser.new_page()
|
||||||
|
await page.goto("https://google.com")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
await summarize_page(page)
|
||||||
asyncio.run(main())
|
|
||||||
|
await browser.close()
|
||||||
|
|
||||||
|
# %%
|
||||||
|
await main()
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
## Output
|
||||||
# db.py
|
```html
|
||||||
import sqlite3, json, os
|
==================================================
|
||||||
|
Google
|
||||||
|
==================================================
|
||||||
|
|
||||||
class DB(sqlite3.Connection):
|
Google 정보
|
||||||
def __init__(self, db_name=".db.sqlite"):
|
|
||||||
super().__init__(os.path.expanduser(db_name))
|
|
||||||
with self:
|
|
||||||
self.execute('''
|
|
||||||
CREATE TABLE IF NOT EXISTS kv_store
|
|
||||||
(key TEXT PRIMARY KEY, value BLOB)
|
|
||||||
''')
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
스토어 Gmail 이미지 로그인 무엇에 관한 의견인지 선택하세요. 더보기 삭제 삭제 부적절한 예상 검색어 신고 Google 지원 언어:
|
||||||
value = value if isinstance(value, bytes) else json.dumps(value)
|
English 대한민국 광고 비즈니스 검색의 원리 개인정보처리방침 약관 설정 검색 설정 고급검색 Google 검색에 표시되는 데이터 검색 기록
|
||||||
with self:
|
검색 도움말 의견 보내기 어두운 테마: 사용 안함 Google 앱
|
||||||
result = self.execute('''
|
|
||||||
INSERT OR REPLACE INTO kv_store
|
|
||||||
(key, value) VALUES (?, ?)
|
|
||||||
''', (key, value)).rowcount
|
|
||||||
return {"modified_count": result}
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
--------------------------------------------------
|
||||||
with self:
|
|
||||||
result = self.execute('''
|
|
||||||
SELECT value FROM kv_store
|
|
||||||
WHERE key = ?
|
|
||||||
''', (key,)).fetchone()
|
|
||||||
if result:
|
|
||||||
if isinstance(value := result[0], str):
|
|
||||||
try: return json.loads(value)
|
|
||||||
except json.JSONDecodeError: pass
|
|
||||||
return value
|
|
||||||
|
|
||||||
def delete(self, key):
|
<input name="btnK" type="submit" value="Google 검색" aria-label="Google 검색" role="button">
|
||||||
with self:
|
<input name="btnI" type="submit" value="I’m Feeling Lucky" aria-label="I’m Feeling Lucky">
|
||||||
result = self.execute('''
|
<textarea id="APjFqb" name="q" aria-label="검색" role="combobox">
|
||||||
DELETE FROM kv_store
|
|
||||||
WHERE key = ?
|
|
||||||
''', (key,)).rowcount
|
|
||||||
return {"deleted_count": result}
|
|
||||||
|
|
||||||
def keys(self, pattern="*"):
|
--------------------------------------------------
|
||||||
pattern = pattern.translate(str.maketrans(
|
|
||||||
{"\\": "\\\\", "%": "\\%", "_": "\\_", "*": "%", "?": "_"}))
|
|
||||||
with self:
|
|
||||||
result = self.execute('''
|
|
||||||
SELECT key FROM kv_store
|
|
||||||
WHERE key LIKE ? ESCAPE '\\'
|
|
||||||
''', (pattern,)).fetchall()
|
|
||||||
return [row[0] for row in result]
|
|
||||||
|
|
||||||
def __repr__(self): return repr(self.keys())
|
|
||||||
|
|
||||||
def exists(self, key):
|
|
||||||
with self:
|
|
||||||
result = self.execute('''
|
|
||||||
SELECT 1 FROM kv_store
|
|
||||||
WHERE key = ?
|
|
||||||
LIMIT 1
|
|
||||||
''', (key,)).fetchone()
|
|
||||||
return bool(result)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
db = DB('~/db.sqlite')
|
|
||||||
|
|
||||||
# 문자열 저장 및 조회
|
|
||||||
db["hello"] = "world"
|
|
||||||
print(db["hello"]) # 출력: world (str 타입)
|
|
||||||
|
|
||||||
# 숫자 저장 및 조회
|
|
||||||
db["number"] = 42
|
|
||||||
print(db["number"]) # 출력: 42 (int 타입)
|
|
||||||
|
|
||||||
# 바이너리 데이터 저장 및 조회
|
|
||||||
db["binary"] = b"binary data"
|
|
||||||
print(db["binary"]) # 출력: b'binary data' (bytes 타입)
|
|
||||||
|
|
||||||
# 복잡한 객체 저장
|
|
||||||
complex_obj = {"name": "John", "age": 30, "city": "New York"}
|
|
||||||
db["complex"] = complex_obj
|
|
||||||
loaded_obj = db["complex"]
|
|
||||||
print(
|
|
||||||
loaded_obj
|
|
||||||
) # 출력: {'name': 'John', 'age': 30, 'city': 'New York'} (dict 타입)
|
|
||||||
|
|
||||||
db["test_key"] = "test_value"
|
|
||||||
|
|
||||||
print(db.exists("test_key")) # True
|
|
||||||
print(db.exists("non_existent_key")) # False
|
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user