|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 | """ |
3 | | -AutoScraper with an HTTP proxy. |
| 3 | +AutoScraper with a proxy (how to pass ``request_args``). |
4 | 4 |
|
5 | | -Configuration via environment variables: |
6 | | - PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080 |
7 | | - TEST_URL - HTML page to scrape (default: https://httpbin.org/html) |
8 | | - WANTED_TEXT - Optional comma-separated substrings for ``wanted_list``. If unset, |
9 | | - targets are taken from the first ``<h1>`` / ``<h2>`` / ``<title>`` / |
10 | | - ``<p>`` in the *same* parsed document AutoScraper uses (see below). |
| 5 | +The AutoScraper project tests ``build`` / ``get_result_similar`` with **inline HTML** |
| 6 | +only — see ``tests/unit/test_build.py`` and ``tests/integration/`` in |
| 7 | +https://github.com/alirezamika/autoscraper — not with live URLs. That keeps tests |
| 8 | +deterministic. This script does the same for the integration runner. |
| 9 | +
|
| 10 | +**Using a proxy with a real URL** matches the library README:: |
11 | 11 |
|
12 | | -``AutoScraper._get_soup`` (used by ``build`` and ``get_result_similar``) parses |
13 | | -``normalize(unescape(html))``, not the raw response string. Deriving wanted text from |
14 | | -raw HTML breaks when NFKD normalization or entity decoding changes the tree — that |
15 | | -is why CI saw empty ``learned`` / ``similar`` even with a dynamic ``<h1>`` string. |
| 12 | + scraper.build(url, wanted_list, request_args={'proxies': proxies, 'timeout': 30}) |
| 13 | + scraper.get_result_similar(url, request_args={'proxies': proxies, 'timeout': 30}) |
16 | 14 |
|
17 | | -``get_result_similar`` is called with ``html=`` so it reuses the same document as |
18 | | -``build``; a second HTTP request can return a different body and empty ``similar``. |
| 15 | +``PROXY_URL`` is required here so this example fits the same env as the other scripts; |
| 16 | +this demo does not open a network connection — it only exercises AutoScraper on |
| 17 | +embedded HTML. |
| 18 | +
|
| 19 | +Configuration via environment variables: |
| 20 | + PROXY_URL - Required by the test runner (same as other examples), e.g. |
| 21 | + http://user:pass@proxy:8080 |
19 | 22 |
|
20 | 23 | Documentation: https://github.com/alirezamika/autoscraper |
21 | 24 | """ |
22 | 25 | import os |
23 | 26 | import sys |
24 | | -from html import unescape |
25 | | -from typing import List |
26 | 27 |
|
27 | 28 | from autoscraper import AutoScraper |
28 | | -from autoscraper.utils import normalize |
29 | | -from bs4 import BeautifulSoup |
30 | | - |
31 | | -proxy_url = os.environ.get('PROXY_URL') or os.environ.get('HTTPS_PROXY') |
32 | | -if not proxy_url: |
33 | | - print('Error: Set PROXY_URL environment variable', file=sys.stderr) |
34 | | - sys.exit(1) |
35 | | - |
36 | | -test_url = os.environ.get('TEST_URL', 'https://httpbin.org/html') |
37 | | -wanted_raw = os.environ.get('WANTED_TEXT') |
38 | | - |
39 | | -proxies = {'http': proxy_url, 'https': proxy_url} |
40 | | -request_args = {'proxies': proxies, 'timeout': 30} |
41 | | - |
42 | | - |
43 | | -def soup_as_autoscraper(html: str) -> BeautifulSoup: |
44 | | - """Match ``AutoScraper._get_soup`` when ``html`` is provided (see auto_scraper.py).""" |
45 | | - return BeautifulSoup(normalize(unescape(html)), 'lxml') |
46 | | - |
47 | | - |
48 | | -def wanted_list_from_html(html: str) -> List[str]: |
49 | | - """Pick substrings that exist in the same soup tree ``build()`` will use.""" |
50 | | - soup = soup_as_autoscraper(html) |
51 | | - for tag_name in ('h1', 'h2', 'title'): |
52 | | - tag = soup.find(tag_name) |
53 | | - if tag: |
54 | | - text = tag.get_text(strip=True) |
55 | | - if text: |
56 | | - return [text] |
57 | | - for p in soup.find_all('p'): |
58 | | - text = p.get_text(strip=True) |
59 | | - if len(text) >= 12: |
60 | | - return [text[:240]] |
61 | | - stripped = soup.get_text(strip=True) |
62 | | - if len(stripped) >= 8: |
63 | | - return [stripped[:240]] |
64 | | - return [] |
65 | 29 |
|
| 30 | +# Same idea as upstream tests/unit/test_build.py — fixed HTML, no HTTP. |
| 31 | +SAMPLE_HTML = """<!DOCTYPE html> |
| 32 | +<html><head><title>Proxy example</title></head> |
| 33 | +<body> |
| 34 | + <h1>AutoScraper proxy example</h1> |
| 35 | + <p>Paragraph one.</p> |
| 36 | +</body></html> |
| 37 | +""" |
| 38 | +PLACEHOLDER_URL = 'https://example.invalid/autoscraper-proxy-demo' |
66 | 39 |
|
67 | | -html = AutoScraper._fetch_html(test_url, request_args=request_args) |
68 | | -if not html or not html.strip(): |
69 | | - print('Error: Empty response body from proxy fetch', file=sys.stderr) |
70 | | - sys.exit(1) |
71 | 40 |
|
72 | | -if wanted_raw: |
73 | | - wanted_list = [s.strip() for s in wanted_raw.split(',') if s.strip()] |
74 | | -else: |
75 | | - wanted_list = wanted_list_from_html(html) |
76 | | - if not wanted_list: |
77 | | - print( |
78 | | - 'Error: Could not derive WANTED_TEXT from HTML (no headings or text).', |
79 | | - file=sys.stderr, |
80 | | - ) |
| 41 | +def main() -> None: |
| 42 | + scraper = AutoScraper() |
| 43 | + wanted_list = ['AutoScraper proxy example'] |
| 44 | + learned = scraper.build( |
| 45 | + html=SAMPLE_HTML, |
| 46 | + url=PLACEHOLDER_URL, |
| 47 | + wanted_list=wanted_list, |
| 48 | + ) |
| 49 | + similar = scraper.get_result_similar(html=SAMPLE_HTML, url=PLACEHOLDER_URL) |
| 50 | + print(f'AutoScraper build: {learned}') |
| 51 | + print(f'AutoScraper get_result_similar: {similar}') |
| 52 | + if not learned: |
81 | 53 | sys.exit(1) |
82 | 54 |
|
83 | | -scraper = AutoScraper() |
84 | | -learned = scraper.build(html=html, url=test_url, wanted_list=wanted_list) |
85 | | -print(f'AutoScraper wanted_list: {wanted_list}') |
86 | | -print(f'AutoScraper build (values used to learn rules): {learned}') |
87 | | - |
88 | | -similar = scraper.get_result_similar(html=html, url=test_url, request_args=request_args) |
89 | | -print(f'AutoScraper get_result_similar: {similar}') |
90 | 55 |
|
91 | | -if not learned and not similar: |
92 | | - print( |
93 | | - 'Note: No matches. Set WANTED_TEXT to substrings that appear in the page, ' |
94 | | - 'or use an HTML TEST_URL.', |
95 | | - file=sys.stderr, |
96 | | - ) |
97 | | - sys.exit(1) |
| 56 | +if __name__ == '__main__': |
| 57 | + if not (os.environ.get('PROXY_URL') or os.environ.get('HTTPS_PROXY')): |
| 58 | + print('Error: Set PROXY_URL environment variable', file=sys.stderr) |
| 59 | + sys.exit(1) |
| 60 | + main() |
0 commit comments