webdown 0.4.1__py3-none-any.whl
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.
- webdown/__init__.py +77 -0
- webdown/cli.py +284 -0
- webdown/converter.py +422 -0
- webdown/tests/__init__.py +1 -0
- webdown/tests/test_cli.py +334 -0
- webdown/tests/test_converter.py +416 -0
- webdown/tests/test_integration.py +95 -0
- webdown-0.4.1.dist-info/LICENSE +21 -0
- webdown-0.4.1.dist-info/METADATA +341 -0
- webdown-0.4.1.dist-info/RECORD +12 -0
- webdown-0.4.1.dist-info/WHEEL +4 -0
- webdown-0.4.1.dist-info/entry_points.txt +3 -0
webdown/__init__.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Webdown: Convert web pages to markdown.
|
|
2
|
+
|
|
3
|
+
Webdown is a command-line tool and Python library for converting web pages to
|
|
4
|
+
clean, readable Markdown format. It provides a comprehensive set of options
|
|
5
|
+
for customizing the conversion process.
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
- Convert web pages to clean, readable Markdown
|
|
10
|
+
- Extract specific content using CSS selectors
|
|
11
|
+
- Generate table of contents from headings
|
|
12
|
+
- Control link and image handling
|
|
13
|
+
- Customize Markdown formatting style
|
|
14
|
+
- Show progress bar for large downloads
|
|
15
|
+
- Configure text wrapping and line breaks
|
|
16
|
+
|
|
17
|
+
## Command-line Usage
|
|
18
|
+
|
|
19
|
+
Webdown provides a command-line interface for easy conversion of web pages to Markdown.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Basic usage
|
|
23
|
+
webdown https://example.com # Output to stdout
|
|
24
|
+
webdown https://example.com -o output.md # Output to file
|
|
25
|
+
webdown https://example.com -c -t # Compact output with TOC
|
|
26
|
+
|
|
27
|
+
# Advanced options
|
|
28
|
+
webdown https://example.com -s "main" -I -c -w 80 -o output.md
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**For detailed CLI documentation and all available options,**
|
|
32
|
+
**see the [CLI module](./webdown/cli.html).**
|
|
33
|
+
|
|
34
|
+
## Library Usage
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
# Simple conversion
|
|
38
|
+
from webdown import convert_url_to_markdown
|
|
39
|
+
markdown = convert_url_to_markdown("https://example.com")
|
|
40
|
+
|
|
41
|
+
# Using the configuration object
|
|
42
|
+
from webdown import WebdownConfig, convert_url_to_markdown
|
|
43
|
+
config = WebdownConfig(
|
|
44
|
+
url="https://example.com",
|
|
45
|
+
include_toc=True,
|
|
46
|
+
css_selector="main",
|
|
47
|
+
body_width=80
|
|
48
|
+
)
|
|
49
|
+
markdown = convert_url_to_markdown(config)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
See the API documentation for detailed descriptions of all options.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
__version__ = "0.4.1"
|
|
56
|
+
|
|
57
|
+
# Import CLI module
|
|
58
|
+
from webdown import cli
|
|
59
|
+
|
|
60
|
+
# Import key classes and functions for easy access
|
|
61
|
+
from webdown.converter import (
|
|
62
|
+
WebdownConfig,
|
|
63
|
+
WebdownError,
|
|
64
|
+
convert_url_to_markdown,
|
|
65
|
+
fetch_url,
|
|
66
|
+
html_to_markdown,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Define public API
|
|
70
|
+
__all__ = [
|
|
71
|
+
"WebdownConfig",
|
|
72
|
+
"WebdownError",
|
|
73
|
+
"convert_url_to_markdown",
|
|
74
|
+
"fetch_url",
|
|
75
|
+
"html_to_markdown",
|
|
76
|
+
"cli",
|
|
77
|
+
]
|
webdown/cli.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""Command-line interface for webdown.
|
|
2
|
+
|
|
3
|
+
This module provides the command-line interface (CLI) for Webdown, a tool for
|
|
4
|
+
converting web pages to clean, readable Markdown format. The CLI allows users to
|
|
5
|
+
customize various aspects of the conversion process, from content selection to
|
|
6
|
+
formatting options.
|
|
7
|
+
|
|
8
|
+
## Basic Usage
|
|
9
|
+
|
|
10
|
+
The most basic usage is to simply provide a URL:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
webdown https://example.com
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This will fetch the web page and convert it to Markdown,
|
|
17
|
+
displaying the result to stdout.
|
|
18
|
+
To save the output to a file:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
webdown https://example.com -o output.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Common Options
|
|
25
|
+
|
|
26
|
+
The CLI offers various options to customize the conversion:
|
|
27
|
+
|
|
28
|
+
* `-o, --output FILE`: Write output to FILE instead of stdout
|
|
29
|
+
* `-t, --toc`: Generate a table of contents based on headings
|
|
30
|
+
* `-L, --no-links`: Strip hyperlinks, converting them to plain text
|
|
31
|
+
* `-I, --no-images`: Exclude images from the output
|
|
32
|
+
* `-s, --css SELECTOR`: Extract only content matching the CSS selector (e.g., "main")
|
|
33
|
+
* `-c, --compact`: Remove excessive blank lines from the output
|
|
34
|
+
* `-w, --width N`: Set line width for wrapped text (0 for no wrapping)
|
|
35
|
+
* `-p, --progress`: Show download progress bar
|
|
36
|
+
* `-V, --version`: Show version information and exit
|
|
37
|
+
* `-h, --help`: Show help message and exit
|
|
38
|
+
|
|
39
|
+
## Advanced Options
|
|
40
|
+
|
|
41
|
+
Advanced formatting options for fine-tuning the Markdown output:
|
|
42
|
+
|
|
43
|
+
* `--single-line-break`: Use single line breaks instead of two line breaks
|
|
44
|
+
* `--unicode`: Use Unicode characters instead of ASCII equivalents
|
|
45
|
+
* `--tables-as-html`: Keep tables as HTML instead of converting to Markdown
|
|
46
|
+
* `--emphasis-mark CHAR`: Character(s) to use for emphasis (default: '_')
|
|
47
|
+
* `--strong-mark CHARS`: Character(s) to use for strong emphasis (default: '**')
|
|
48
|
+
|
|
49
|
+
## Example Scenarios
|
|
50
|
+
|
|
51
|
+
1. Basic conversion with a table of contents:
|
|
52
|
+
```bash
|
|
53
|
+
webdown https://example.com -t -o output.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
2. Extract only the main content area with compact output and text wrapping:
|
|
57
|
+
```bash
|
|
58
|
+
webdown https://example.com -s "main" -c -w 80 -o output.md
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
3. Create a plain text version (no links or images):
|
|
62
|
+
```bash
|
|
63
|
+
webdown https://example.com -L -I -o text_only.md
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
4. Show download progress for large pages and customize Markdown formatting:
|
|
67
|
+
```bash
|
|
68
|
+
webdown https://example.com -p --single-line-break --unicode -o output.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
5. Extract content from a specific div and customize emphasis markers:
|
|
72
|
+
```bash
|
|
73
|
+
webdown https://example.com -s "#content" --emphasis-mark "*" \
|
|
74
|
+
--strong-mark "__" -o output.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The entry point is the `main()` function, which is called when the command
|
|
78
|
+
`webdown` is executed.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
import argparse
|
|
82
|
+
import sys
|
|
83
|
+
from typing import List, Optional
|
|
84
|
+
|
|
85
|
+
from webdown import __version__
|
|
86
|
+
from webdown.converter import WebdownConfig, convert_url_to_markdown
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def parse_args(args: Optional[List[str]] = None) -> argparse.Namespace:
|
|
90
|
+
"""Parse command line arguments.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
args: Command line arguments (defaults to sys.argv[1:] if None)
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Parsed arguments
|
|
97
|
+
"""
|
|
98
|
+
parser = argparse.ArgumentParser(
|
|
99
|
+
description="Convert web pages to clean, readable Markdown format.",
|
|
100
|
+
epilog="For more information: https://github.com/kelp/webdown",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Required argument
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
"url",
|
|
106
|
+
help="URL of the web page to convert (e.g., https://example.com)",
|
|
107
|
+
nargs="?",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Input/Output options
|
|
111
|
+
io_group = parser.add_argument_group("Input/Output Options")
|
|
112
|
+
io_group.add_argument(
|
|
113
|
+
"-o",
|
|
114
|
+
"--output",
|
|
115
|
+
metavar="FILE",
|
|
116
|
+
help="Write Markdown output to FILE instead of stdout",
|
|
117
|
+
)
|
|
118
|
+
io_group.add_argument(
|
|
119
|
+
"-p",
|
|
120
|
+
"--progress",
|
|
121
|
+
action="store_true",
|
|
122
|
+
help="Display a progress bar during download (useful for large pages)",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Content options
|
|
126
|
+
content_group = parser.add_argument_group("Content Selection")
|
|
127
|
+
content_group.add_argument(
|
|
128
|
+
"-s",
|
|
129
|
+
"--css",
|
|
130
|
+
metavar="SELECTOR",
|
|
131
|
+
help="Extract content matching CSS selector (e.g., 'main', '.content')",
|
|
132
|
+
)
|
|
133
|
+
content_group.add_argument(
|
|
134
|
+
"-L",
|
|
135
|
+
"--no-links",
|
|
136
|
+
action="store_true",
|
|
137
|
+
help="Convert hyperlinks to plain text (remove all link markup)",
|
|
138
|
+
)
|
|
139
|
+
content_group.add_argument(
|
|
140
|
+
"-I",
|
|
141
|
+
"--no-images",
|
|
142
|
+
action="store_true",
|
|
143
|
+
help="Exclude images from the output completely",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Formatting options
|
|
147
|
+
format_group = parser.add_argument_group("Formatting Options")
|
|
148
|
+
format_group.add_argument(
|
|
149
|
+
"-t",
|
|
150
|
+
"--toc",
|
|
151
|
+
action="store_true",
|
|
152
|
+
help="Generate a table of contents based on headings in the document",
|
|
153
|
+
)
|
|
154
|
+
format_group.add_argument(
|
|
155
|
+
"-c",
|
|
156
|
+
"--compact",
|
|
157
|
+
action="store_true",
|
|
158
|
+
help="Remove excessive blank lines for more compact output",
|
|
159
|
+
)
|
|
160
|
+
format_group.add_argument(
|
|
161
|
+
"-w",
|
|
162
|
+
"--width",
|
|
163
|
+
type=int,
|
|
164
|
+
default=0,
|
|
165
|
+
metavar="N",
|
|
166
|
+
help="Set line width (0 disables wrapping, 80 recommended for readability)",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Add advanced HTML2Text options
|
|
170
|
+
advanced_group = parser.add_argument_group("Advanced Options")
|
|
171
|
+
advanced_group.add_argument(
|
|
172
|
+
"--single-line-break",
|
|
173
|
+
action="store_true",
|
|
174
|
+
help="Use single line breaks instead of double (creates more compact output)",
|
|
175
|
+
)
|
|
176
|
+
advanced_group.add_argument(
|
|
177
|
+
"--unicode",
|
|
178
|
+
action="store_true",
|
|
179
|
+
help="Use Unicode characters instead of ASCII equivalents",
|
|
180
|
+
)
|
|
181
|
+
advanced_group.add_argument(
|
|
182
|
+
"--tables-as-html",
|
|
183
|
+
action="store_true",
|
|
184
|
+
help="Keep tables as HTML instead of converting to Markdown",
|
|
185
|
+
)
|
|
186
|
+
advanced_group.add_argument(
|
|
187
|
+
"--emphasis-mark",
|
|
188
|
+
default="_",
|
|
189
|
+
metavar="CHAR",
|
|
190
|
+
help="Character(s) for emphasis (default: '_', alternative: '*')",
|
|
191
|
+
)
|
|
192
|
+
advanced_group.add_argument(
|
|
193
|
+
"--strong-mark",
|
|
194
|
+
default="**",
|
|
195
|
+
metavar="CHARS",
|
|
196
|
+
help="Character(s) for strong emphasis (default: '**', alt: '__')",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Meta options
|
|
200
|
+
meta_group = parser.add_argument_group("Meta Options")
|
|
201
|
+
meta_group.add_argument(
|
|
202
|
+
"-V",
|
|
203
|
+
"--version",
|
|
204
|
+
action="version",
|
|
205
|
+
version=f"%(prog)s {__version__}",
|
|
206
|
+
help="Show version information and exit",
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return parser.parse_args(args)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def main(args: Optional[List[str]] = None) -> int:
|
|
213
|
+
"""Execute the webdown command-line interface.
|
|
214
|
+
|
|
215
|
+
This function is the main entry point for the webdown command-line tool.
|
|
216
|
+
It handles the entire workflow:
|
|
217
|
+
1. Parsing command-line arguments
|
|
218
|
+
2. Converting the URL to Markdown with the specified options
|
|
219
|
+
3. Writing the output to a file or stdout
|
|
220
|
+
4. Error handling and reporting
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
args: Command line arguments as a list of strings. If None, defaults to
|
|
224
|
+
sys.argv[1:] (the command-line arguments passed to the script).
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Exit code: 0 for success, 1 for errors
|
|
228
|
+
|
|
229
|
+
Examples:
|
|
230
|
+
>>> main(['https://example.com']) # Convert and print to stdout
|
|
231
|
+
0
|
|
232
|
+
>>> main(['https://example.com', '-o', 'output.md']) # Write to file
|
|
233
|
+
0
|
|
234
|
+
>>> main(['invalid-url']) # Handle error
|
|
235
|
+
1
|
|
236
|
+
"""
|
|
237
|
+
try:
|
|
238
|
+
parsed_args = parse_args(args)
|
|
239
|
+
|
|
240
|
+
# If no URL provided, show help
|
|
241
|
+
if parsed_args.url is None:
|
|
242
|
+
# This will print help and exit
|
|
243
|
+
parse_args(
|
|
244
|
+
["-h"]
|
|
245
|
+
) # pragma: no cover - this exits so coverage tools can't track it
|
|
246
|
+
return 0 # pragma: no cover - unreachable after SystemExit
|
|
247
|
+
|
|
248
|
+
# Create a config object from command-line arguments
|
|
249
|
+
config = WebdownConfig(
|
|
250
|
+
# Basic options
|
|
251
|
+
url=parsed_args.url,
|
|
252
|
+
include_toc=parsed_args.toc,
|
|
253
|
+
include_links=not parsed_args.no_links,
|
|
254
|
+
include_images=not parsed_args.no_images,
|
|
255
|
+
css_selector=parsed_args.css,
|
|
256
|
+
compact_output=parsed_args.compact,
|
|
257
|
+
body_width=parsed_args.width,
|
|
258
|
+
show_progress=parsed_args.progress,
|
|
259
|
+
# Advanced options
|
|
260
|
+
single_line_break=parsed_args.single_line_break,
|
|
261
|
+
unicode_snob=parsed_args.unicode,
|
|
262
|
+
tables_as_html=parsed_args.tables_as_html,
|
|
263
|
+
emphasis_mark=parsed_args.emphasis_mark,
|
|
264
|
+
strong_mark=parsed_args.strong_mark,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Convert using the config object
|
|
268
|
+
markdown = convert_url_to_markdown(config)
|
|
269
|
+
|
|
270
|
+
if parsed_args.output:
|
|
271
|
+
with open(parsed_args.output, "w", encoding="utf-8") as f:
|
|
272
|
+
f.write(markdown)
|
|
273
|
+
else:
|
|
274
|
+
sys.stdout.write(markdown)
|
|
275
|
+
|
|
276
|
+
return 0
|
|
277
|
+
|
|
278
|
+
except Exception as e:
|
|
279
|
+
sys.stderr.write(f"Error: {str(e)}\n")
|
|
280
|
+
return 1
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
if __name__ == "__main__": # pragma: no cover - difficult to test main module block
|
|
284
|
+
sys.exit(main())
|