scrapedesk 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Engr. Mubashir Hussain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: scrapedesk
3
+ Version: 1.0.0
4
+ Summary: A friendly desktop web scraper: grab images, tables, links and text from any website and export to Excel, CSV, JSON or SQLite.
5
+ Author-email: "Engr. Mubashir Hussain" <mubashir6u@gmail.com>
6
+ License-Expression: MIT
7
+ Keywords: web scraping,scraper,gui,tkinter,images,tables,excel,csv,crawler,beautifulsoup,data extraction,desktop
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: MacOS X
10
+ Classifier: Environment :: Win32 (MS Windows)
11
+ Classifier: Environment :: X11 Applications
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Internet :: WWW/HTTP
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
25
+ Classifier: Topic :: Office/Business
26
+ Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: requests>=2.31
31
+ Requires-Dist: beautifulsoup4>=4.12
32
+ Requires-Dist: lxml>=5.0
33
+ Requires-Dist: pandas>=2.0
34
+ Requires-Dist: openpyxl>=3.1
35
+ Requires-Dist: pillow>=10.0
36
+ Provides-Extra: js
37
+ Requires-Dist: playwright>=1.40; extra == "js"
38
+ Provides-Extra: selenium
39
+ Requires-Dist: selenium>=4.15; extra == "selenium"
40
+ Provides-Extra: all
41
+ Requires-Dist: playwright>=1.40; extra == "all"
42
+ Requires-Dist: selenium>=4.15; extra == "all"
43
+ Provides-Extra: dev
44
+ Requires-Dist: pytest>=7; extra == "dev"
45
+ Requires-Dist: build>=1.0; extra == "dev"
46
+ Requires-Dist: twine>=5; extra == "dev"
47
+ Dynamic: license-file
48
+
49
+ # ScrapeDesk
50
+
51
+ **A friendly desktop web scraper.** Paste a link, choose what you want (images, tables, links, text, emails or custom fields) and export it to Excel, CSV, JSON, SQLite and more. You don't need to write any code.
52
+
53
+ ```bash
54
+ pip install scrapedesk
55
+ scrapedesk
56
+ ```
57
+
58
+ Works on Windows, macOS and Linux with Python 3.9+.
59
+
60
+ ---
61
+
62
+ ## Highlights
63
+
64
+ | | |
65
+ |---|---|
66
+ | **Easy to use** | Sidebar navigation, big toggle cards, live result counters, tooltips, notifications, light and dark mode, and keyboard shortcuts |
67
+ | **Images** | Thumbnail gallery with click-to-select and a full-size viewer. Finds `img`, `srcset`, lazy-loaded (`data-src` and more), `<picture>`, CSS backgrounds, `og:image`, icons and linked image files |
68
+ | **Smart downloads** | Filter by type, width/height and file size. Removes duplicates, downloads in parallel, renames, and converts to PNG/JPG/WEBP |
69
+ | **Tables** | Every `<table>`, including merged cells (`colspan`/`rowspan`) and multi-row headers. Can also turn product grids and lists into tables. Sort, filter, merge, and copy to Excel |
70
+ | **Exports** | Excel (one sheet per table), CSV, TSV, JSON, HTML, SQLite and Markdown, or *everything* in one workbook |
71
+ | **Custom fields** | Pick exact values (title, price, rating, link…) with CSS or XPath and get one row per item |
72
+ | **More pages** | Follows "Next page" pagination and crawls links with depth, page limits and include/exclude rules |
73
+ | **Tough sites** | Browser identities, headers, cookies, proxy, retries, request delay, robots.txt, and optional JavaScript rendering |
74
+
75
+ ## Install
76
+
77
+ ```bash
78
+ pip install scrapedesk
79
+ ```
80
+
81
+ Start the app:
82
+
83
+ ```bash
84
+ scrapedesk # or: python -m scrapedesk
85
+ scrapedesk https://example.com # open with a URL already filled in
86
+ ```
87
+
88
+ > **Linux:** tkinter is sometimes packaged separately: `sudo apt install python3-tk`.
89
+
90
+ ### JavaScript-heavy websites (optional)
91
+
92
+ If a site builds its content with JavaScript (React or Vue apps, infinite scroll), install the browser extra and turn on **Settings → JavaScript websites → Playwright**:
93
+
94
+ ```bash
95
+ pip install "scrapedesk[js]"
96
+ python -m playwright install chromium
97
+ ```
98
+
99
+ If you skip the last step, ScrapeDesk falls back to an installed Google Chrome or Microsoft Edge.
100
+
101
+ ## How to use
102
+
103
+ 1. **Home:** paste a URL (or several), then click the cards for what you want to collect and press **Start**.
104
+ 2. Watch the counters update. When the job finishes, a notification takes you to the results.
105
+ 3. **Images:** click thumbnails to select them, double-click to see full size, then **Download selected**.
106
+ 4. **Tables:** pick a table, then **Export** it (Excel, CSV…) or **Copy** it straight into Excel.
107
+ 5. **Custom Fields:** press **Load example** to see how product names and prices are extracted.
108
+ 6. Press **Ctrl+E** to export everything in one Excel workbook.
109
+
110
+ Keyboard shortcuts:
111
+
112
+ | Keys | Action |
113
+ |---|---|
114
+ | Enter / Ctrl+Enter | Start |
115
+ | Esc | Stop |
116
+ | Ctrl+1…9 | Switch section |
117
+ | Ctrl+E | Export all |
118
+ | Ctrl+D | Dark mode |
119
+ | F1 | Help |
120
+
121
+ ## Command line
122
+
123
+ Everything also works without the window:
124
+
125
+ ```bash
126
+ # all images wider than 300 px
127
+ scrapedesk-cli https://example.com --images --download --min-width 300 --types jpg,png
128
+
129
+ # every table to Excel
130
+ scrapedesk-cli https://example.com/stats --tables -o stats.xlsx
131
+
132
+ # one row per product across 50 pages
133
+ scrapedesk-cli https://books.toscrape.com --paginate --max-pages 50 \
134
+ --row article.product_pod --css "title=h3 a@title" --css "price=.price_color" -o books.csv
135
+
136
+ # crawl a site and export everything
137
+ scrapedesk-cli https://example.com --crawl --depth 2 --max-pages 100 --report everything.xlsx
138
+ ```
139
+
140
+ Run `scrapedesk-cli --help` for all options.
141
+
142
+ ## Use it from Python
143
+
144
+ ```python
145
+ from scrapedesk import ScrapeSettings, WebScraper
146
+ from scrapedesk.exporters import export_dataframes, tables_to_frames
147
+
148
+ settings = ScrapeSettings(extract_images=True, extract_tables=True, min_width=200)
149
+ scraper = WebScraper(settings)
150
+ pages = scraper.run(["https://example.com"])
151
+
152
+ tables = [t for p in pages for t in p.tables]
153
+ export_dataframes(tables_to_frames(tables), "tables.xlsx")
154
+ scraper.download_images([img for p in pages for img in p.images])
155
+ ```
156
+
157
+ ## Responsible use
158
+
159
+ Only scrape content you are allowed to access. Respect each website's terms of service, robots.txt (there is a setting for it) and rate limits (use the delay setting), and follow privacy laws such as GDPR when you collect personal data. ScrapeDesk does not bypass logins, CAPTCHAs or anti-bot protection.
160
+
161
+ ## License
162
+
163
+ MIT
@@ -0,0 +1,115 @@
1
+ # ScrapeDesk
2
+
3
+ **A friendly desktop web scraper.** Paste a link, choose what you want (images, tables, links, text, emails or custom fields) and export it to Excel, CSV, JSON, SQLite and more. You don't need to write any code.
4
+
5
+ ```bash
6
+ pip install scrapedesk
7
+ scrapedesk
8
+ ```
9
+
10
+ Works on Windows, macOS and Linux with Python 3.9+.
11
+
12
+ ---
13
+
14
+ ## Highlights
15
+
16
+ | | |
17
+ |---|---|
18
+ | **Easy to use** | Sidebar navigation, big toggle cards, live result counters, tooltips, notifications, light and dark mode, and keyboard shortcuts |
19
+ | **Images** | Thumbnail gallery with click-to-select and a full-size viewer. Finds `img`, `srcset`, lazy-loaded (`data-src` and more), `<picture>`, CSS backgrounds, `og:image`, icons and linked image files |
20
+ | **Smart downloads** | Filter by type, width/height and file size. Removes duplicates, downloads in parallel, renames, and converts to PNG/JPG/WEBP |
21
+ | **Tables** | Every `<table>`, including merged cells (`colspan`/`rowspan`) and multi-row headers. Can also turn product grids and lists into tables. Sort, filter, merge, and copy to Excel |
22
+ | **Exports** | Excel (one sheet per table), CSV, TSV, JSON, HTML, SQLite and Markdown, or *everything* in one workbook |
23
+ | **Custom fields** | Pick exact values (title, price, rating, link…) with CSS or XPath and get one row per item |
24
+ | **More pages** | Follows "Next page" pagination and crawls links with depth, page limits and include/exclude rules |
25
+ | **Tough sites** | Browser identities, headers, cookies, proxy, retries, request delay, robots.txt, and optional JavaScript rendering |
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install scrapedesk
31
+ ```
32
+
33
+ Start the app:
34
+
35
+ ```bash
36
+ scrapedesk # or: python -m scrapedesk
37
+ scrapedesk https://example.com # open with a URL already filled in
38
+ ```
39
+
40
+ > **Linux:** tkinter is sometimes packaged separately: `sudo apt install python3-tk`.
41
+
42
+ ### JavaScript-heavy websites (optional)
43
+
44
+ If a site builds its content with JavaScript (React or Vue apps, infinite scroll), install the browser extra and turn on **Settings → JavaScript websites → Playwright**:
45
+
46
+ ```bash
47
+ pip install "scrapedesk[js]"
48
+ python -m playwright install chromium
49
+ ```
50
+
51
+ If you skip the last step, ScrapeDesk falls back to an installed Google Chrome or Microsoft Edge.
52
+
53
+ ## How to use
54
+
55
+ 1. **Home:** paste a URL (or several), then click the cards for what you want to collect and press **Start**.
56
+ 2. Watch the counters update. When the job finishes, a notification takes you to the results.
57
+ 3. **Images:** click thumbnails to select them, double-click to see full size, then **Download selected**.
58
+ 4. **Tables:** pick a table, then **Export** it (Excel, CSV…) or **Copy** it straight into Excel.
59
+ 5. **Custom Fields:** press **Load example** to see how product names and prices are extracted.
60
+ 6. Press **Ctrl+E** to export everything in one Excel workbook.
61
+
62
+ Keyboard shortcuts:
63
+
64
+ | Keys | Action |
65
+ |---|---|
66
+ | Enter / Ctrl+Enter | Start |
67
+ | Esc | Stop |
68
+ | Ctrl+1…9 | Switch section |
69
+ | Ctrl+E | Export all |
70
+ | Ctrl+D | Dark mode |
71
+ | F1 | Help |
72
+
73
+ ## Command line
74
+
75
+ Everything also works without the window:
76
+
77
+ ```bash
78
+ # all images wider than 300 px
79
+ scrapedesk-cli https://example.com --images --download --min-width 300 --types jpg,png
80
+
81
+ # every table to Excel
82
+ scrapedesk-cli https://example.com/stats --tables -o stats.xlsx
83
+
84
+ # one row per product across 50 pages
85
+ scrapedesk-cli https://books.toscrape.com --paginate --max-pages 50 \
86
+ --row article.product_pod --css "title=h3 a@title" --css "price=.price_color" -o books.csv
87
+
88
+ # crawl a site and export everything
89
+ scrapedesk-cli https://example.com --crawl --depth 2 --max-pages 100 --report everything.xlsx
90
+ ```
91
+
92
+ Run `scrapedesk-cli --help` for all options.
93
+
94
+ ## Use it from Python
95
+
96
+ ```python
97
+ from scrapedesk import ScrapeSettings, WebScraper
98
+ from scrapedesk.exporters import export_dataframes, tables_to_frames
99
+
100
+ settings = ScrapeSettings(extract_images=True, extract_tables=True, min_width=200)
101
+ scraper = WebScraper(settings)
102
+ pages = scraper.run(["https://example.com"])
103
+
104
+ tables = [t for p in pages for t in p.tables]
105
+ export_dataframes(tables_to_frames(tables), "tables.xlsx")
106
+ scraper.download_images([img for p in pages for img in p.images])
107
+ ```
108
+
109
+ ## Responsible use
110
+
111
+ Only scrape content you are allowed to access. Respect each website's terms of service, robots.txt (there is a setting for it) and rate limits (use the delay setting), and follow privacy laws such as GDPR when you collect personal data. ScrapeDesk does not bypass logins, CAPTCHAs or anti-bot protection.
112
+
113
+ ## License
114
+
115
+ MIT
@@ -0,0 +1,74 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "scrapedesk"
7
+ dynamic = ["version"]
8
+ description = "A friendly desktop web scraper: grab images, tables, links and text from any website and export to Excel, CSV, JSON or SQLite."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Engr. Mubashir Hussain", email = "mubashir6u@gmail.com" }]
14
+ keywords = ["web scraping", "scraper", "gui", "tkinter", "images", "tables", "excel", "csv", "crawler",
15
+ "beautifulsoup", "data extraction", "desktop"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: MacOS X",
19
+ "Environment :: Win32 (MS Windows)",
20
+ "Environment :: X11 Applications",
21
+ "Intended Audience :: End Users/Desktop",
22
+ "Intended Audience :: Developers",
23
+ "Intended Audience :: Science/Research",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3 :: Only",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Topic :: Internet :: WWW/HTTP",
33
+ "Topic :: Internet :: WWW/HTTP :: Indexing/Search",
34
+ "Topic :: Office/Business",
35
+ "Topic :: Utilities",
36
+ ]
37
+ dependencies = [
38
+ "requests>=2.31",
39
+ "beautifulsoup4>=4.12",
40
+ "lxml>=5.0",
41
+ "pandas>=2.0",
42
+ "openpyxl>=3.1",
43
+ "pillow>=10.0",
44
+ ]
45
+
46
+ [project.optional-dependencies]
47
+ js = ["playwright>=1.40"]
48
+ selenium = ["selenium>=4.15"]
49
+ all = ["playwright>=1.40", "selenium>=4.15"]
50
+ dev = ["pytest>=7", "build>=1.0", "twine>=5"]
51
+
52
+ [project.scripts]
53
+ scrapedesk-cli = "scrapedesk.cli:main"
54
+
55
+ [project.gui-scripts]
56
+ scrapedesk = "scrapedesk.gui.app:main"
57
+
58
+ # Fill these in once the code is on GitHub - they appear as links on the PyPI page.
59
+ # [project.urls]
60
+ # Homepage = "https://github.com/<your-user>/scrapedesk"
61
+ # Issues = "https://github.com/<your-user>/scrapedesk/issues"
62
+ # Changelog = "https://github.com/<your-user>/scrapedesk/blob/main/CHANGELOG.md"
63
+
64
+ [tool.setuptools.dynamic]
65
+ version = { attr = "scrapedesk.__version__" }
66
+
67
+ [tool.setuptools.packages.find]
68
+ where = ["src"]
69
+
70
+ [tool.setuptools.package-data]
71
+ scrapedesk = ["assets/*.png", "assets/*.ico"]
72
+
73
+ [tool.pytest.ini_options]
74
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ """ScrapeDesk - a friendly desktop web scraper for images, tables, links and text."""
2
+
3
+ __version__ = "1.0.0"
4
+
5
+ from .core import ImageItem, PageResult, ScrapeSettings, TableItem, WebScraper # noqa: E402
6
+
7
+ __all__ = ["ScrapeSettings", "WebScraper", "PageResult", "ImageItem", "TableItem", "__version__"]
@@ -0,0 +1,15 @@
1
+ """`python -m scrapedesk` opens the GUI; `python -m scrapedesk --cli ...` runs the command line."""
2
+
3
+ import sys
4
+
5
+
6
+ def main():
7
+ if len(sys.argv) > 1 and sys.argv[1] == "--cli":
8
+ from .cli import main as cli_main
9
+ return cli_main(sys.argv[2:])
10
+ from .gui.app import main as gui_main
11
+ return gui_main()
12
+
13
+
14
+ if __name__ == "__main__":
15
+ sys.exit(main())
@@ -0,0 +1,100 @@
1
+ """
2
+ Command-line interface for ScrapeDesk (no GUI needed).
3
+
4
+ Examples
5
+ scrapedesk-cli https://example.com --images --download
6
+ scrapedesk-cli https://en.wikipedia.org/wiki/List_of_largest_cities --tables -o cities.xlsx
7
+ scrapedesk-cli https://books.toscrape.com --crawl --max-pages 20 --report report.xlsx
8
+ """
9
+
10
+ import argparse
11
+ import sys
12
+
13
+ from .core import ScrapeSettings, WebScraper, USER_AGENTS
14
+ from . import exporters, __version__
15
+
16
+
17
+ def main(argv=None):
18
+ ap = argparse.ArgumentParser(prog="scrapedesk-cli", description="ScrapeDesk - scrape images, tables, "
19
+ "links and text from websites (command line)")
20
+ ap.add_argument("-V", "--version", action="version", version=f"%(prog)s {__version__}")
21
+ ap.add_argument("urls", nargs="+", help="URL(s) or local .html file(s)")
22
+ ap.add_argument("--images", action="store_true", help="extract images")
23
+ ap.add_argument("--tables", action="store_true", help="extract tables")
24
+ ap.add_argument("--links", action="store_true", help="extract links")
25
+ ap.add_argument("--text", action="store_true", help="extract text/meta/contacts")
26
+ ap.add_argument("--download", action="store_true", help="download the images found")
27
+ ap.add_argument("--dir", help="image download folder")
28
+ ap.add_argument("--min-width", type=int, default=0)
29
+ ap.add_argument("--min-height", type=int, default=0)
30
+ ap.add_argument("--types", help="comma separated image types, e.g. jpg,png,webp")
31
+ ap.add_argument("-o", "--output", help="export tables to this file (.xlsx .csv .json .html .db .md)")
32
+ ap.add_argument("--report", help="export EVERYTHING to .xlsx / .json / .db")
33
+ ap.add_argument("--crawl", action="store_true")
34
+ ap.add_argument("--depth", type=int, default=1)
35
+ ap.add_argument("--max-pages", type=int, default=20)
36
+ ap.add_argument("--paginate", action="store_true", help="follow 'next page' links")
37
+ ap.add_argument("--js", choices=["none", "playwright", "selenium"], default="none")
38
+ ap.add_argument("--delay", type=float, default=0.5)
39
+ ap.add_argument("--proxy", default="")
40
+ ap.add_argument("--ua", choices=list(USER_AGENTS), default="Chrome (Windows)")
41
+ ap.add_argument("--css", action="append", default=[], metavar="NAME=SELECTOR[@attr]",
42
+ help="custom CSS field, e.g. price=.price_color or link='h3 a@href'")
43
+ ap.add_argument("--row", default="", help="record container CSS selector for --css fields")
44
+ ap.add_argument("--profile", help="load settings from a profile .json saved by the GUI")
45
+ a = ap.parse_args(argv)
46
+
47
+ if a.profile:
48
+ with open(a.profile, encoding="utf-8") as fh:
49
+ s = ScrapeSettings.from_json(fh.read())
50
+ else:
51
+ s = ScrapeSettings()
52
+ any_flag = a.images or a.tables or a.links or a.text
53
+ if any_flag or not a.profile:
54
+ everything = not any_flag
55
+ s.extract_images = a.images or everything
56
+ s.extract_tables = a.tables or everything
57
+ s.extract_links = a.links or everything
58
+ s.extract_text = s.extract_meta = s.extract_contacts = a.text or everything
59
+ s.crawl, s.max_depth, s.max_pages, s.follow_pagination = a.crawl, a.depth, a.max_pages, a.paginate
60
+ s.render_js, s.delay, s.proxy, s.user_agent = a.js, a.delay, a.proxy, USER_AGENTS[a.ua]
61
+ s.min_width, s.min_height = a.min_width, a.min_height
62
+ if a.dir:
63
+ s.download_dir = a.dir
64
+ if a.types:
65
+ s.image_types = [t.strip().lower() for t in a.types.split(",")]
66
+ for spec in a.css:
67
+ name, _, q = spec.partition("=")
68
+ q, _, attr = q.partition("@")
69
+ s.custom_selectors.append({"name": name, "type": "css", "query": q, "attr": attr or "text"})
70
+ s.custom_row_selector = a.row
71
+
72
+ sc = WebScraper(s, log=print)
73
+ results = sc.run(a.urls)
74
+ images = [i for r in results for i in r.images]
75
+ tables = [t for r in results for t in r.tables]
76
+ print(f"\nPages: {len(results)} Images: {len(images)} Tables: {len(tables)} "
77
+ f"Links: {sum(len(r.links) for r in results)} Custom rows: {sum(len(r.custom) for r in results)}")
78
+ for t in tables[:20]:
79
+ print(f" - {t.name}: {len(t.rows)} rows x {max(len(x) for x in t.rows)} cols")
80
+ if a.download and images:
81
+ sc.download_images(images)
82
+ if a.output:
83
+ custom = [row for r in results for row in r.custom]
84
+ frames = exporters.tables_to_frames(tables)
85
+ if custom:
86
+ frames = {"Custom": exporters.records_to_df(custom), **frames}
87
+ if frames:
88
+ for f in exporters.export_dataframes(frames, a.output):
89
+ print("saved", f)
90
+ else:
91
+ print("No tables / custom data to export.")
92
+ if a.report:
93
+ for f in exporters.export_full_report(results, a.report):
94
+ print("saved", f)
95
+ sc.close()
96
+ return 0
97
+
98
+
99
+ if __name__ == "__main__":
100
+ sys.exit(main())