{"id":21905061,"url":"https://github.com/kenjyco/webclient-helper","last_synced_at":"2026-01-27T07:35:47.643Z","repository":{"id":54611091,"uuid":"303259809","full_name":"kenjyco/webclient-helper","owner":"kenjyco","description":"Helpful WebClient class to interact with APIs on the web (wrapper to popular requests package)","archived":false,"fork":false,"pushed_at":"2025-07-23T18:10:51.000Z","size":48,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-28T02:58:24.682Z","etag":null,"topics":["api","api-client","beautifulsoup4","http","kenjyco","lxml","python","requests","rest"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kenjyco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-10-12T02:43:47.000Z","updated_at":"2025-07-23T18:10:30.000Z","dependencies_parsed_at":"2024-11-30T18:18:57.890Z","dependency_job_id":"f26a5b8c-3bd1-4289-ba9b-aa6f31c60735","html_url":"https://github.com/kenjyco/webclient-helper","commit_stats":{"total_commits":17,"total_committers":1,"mean_commits":17.0,"dds":0.0,"last_synced_commit":"e4a688e92b5251078f6eeab99004ca77e2d14d1c"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/kenjyco/webclient-helper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Fwebclient-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Fwebclient-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Fwebclient-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Fwebclient-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenjyco","download_url":"https://codeload.github.com/kenjyco/webclient-helper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Fwebclient-helper/sbom","scorecard":{"id":555172,"data":{"date":"2025-08-11","repo":{"name":"github.com/kenjyco/webclient-helper","commit":"b4872622008402acf2a33d237d2533f36f4fd32a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"checks":[{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":2,"reason":"3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"21 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-55x5-fj6c-h6m8","Warn: Project is vulnerable to: PYSEC-2014-9 / GHSA-57qw-cc2g-pv5p","Warn: Project is vulnerable to: PYSEC-2021-19 / GHSA-jq4v-f5q6-mjqq","Warn: Project is vulnerable to: GHSA-pgww-xf46-h92r","Warn: Project is vulnerable to: PYSEC-2022-230 / GHSA-wrxv-2j5q-m38w","Warn: Project is vulnerable to: PYSEC-2018-12 / GHSA-xp26-p53h-6h2p","Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h","Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: PYSEC-2023-212 / GHSA-g4mx-q9vg-27p4","Warn: Project is vulnerable to: PYSEC-2023-207 / GHSA-gwvm-45gx-3cf8","Warn: Project is vulnerable to: PYSEC-2019-133 / GHSA-mh33-7rrq-662w","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: PYSEC-2019-132 / GHSA-r64q-w8jr-g9qp","Warn: Project is vulnerable to: PYSEC-2023-192 / GHSA-v845-jxx5-vc9f","Warn: Project is vulnerable to: PYSEC-2020-148 / GHSA-wqvq-5m8c-6g24","Warn: Project is vulnerable to: PYSEC-2018-32 / GHSA-www2-v7xj-xrc6","Warn: Project is vulnerable to: PYSEC-2021-108"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T12:07:26.787Z","repository_id":54611091,"created_at":"2025-08-20T12:07:26.787Z","updated_at":"2025-08-20T12:07:26.787Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28808128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T07:14:39.408Z","status":"ssl_error","status_checked_at":"2026-01-27T07:14:39.098Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-client","beautifulsoup4","http","kenjyco","lxml","python","requests","rest"],"created_at":"2024-11-28T16:28:18.283Z","updated_at":"2026-01-27T07:35:47.628Z","avatar_url":"https://github.com/kenjyco.png","language":"Python","readme":"A conversational HTTP client library designed for human-centered API development, exploration, and debugging. The library is optimized for developers who value transparency, debugging capability, and workflow flexibility. It shines in scenarios involving API exploration, integration testing, and iterative development where understanding request/response patterns is crucial. Rather than hiding complexity behind abstractions, webclient-helper illuminates it through comprehensive debugging tools and direct access to underlying functionality.\n\nCreate an instance of WebClient and use the HTTP methods (OPTIONS, HEAD, GET, POST, PUT, PATCH, DELETE) to interact with an API. Every HTTP method includes immediate debugger access through `debug=True`.\n\nThe library assumes developer competence, provides full access to underlying session objects, and provides complete history preservation to enable analysis of API interaction patterns.\n\n## Install\n\n```\npip install webclient-helper\n```\n\n### Or, install with beautifulsoup4 and lxml (for HTML parsing support)\n\nInstall system requirements for `lxml`\n\n```\nsudo apt-get install -y libxml2 libxslt1.1 libxml2-dev libxslt1-dev\n```\n\nor\n\n```\nbrew install libxml2\n```\n\nInstall with pip\n\n```\npip install webclient-helper[bs4]\n```\n\n## QuickStart\n\n### Example with the GitHub API\n\nHere's a minimal example showing the library's core philosophy in action:\n\n\u003e Note: Before using the GitHub API, generate a \"personal access token\" at \u003chttps://github.com/settings/tokens/new\u003e and save to your local `~/.bashrc` or `~/.zshrc` file (`export GITHUB_ACCESS_TOKEN=\"ghp_vx...\"`).\n\u003e\n\u003e Review \u003chttps://docs.github.com/en/rest/reference\u003e for endpoints to hit.\n\n```python\nimport webclient_helper as wh\nfrom os import getenv\n\naccess_token = getenv('GITHUB_ACCESS_TOKEN')\n\nclient = wh.WebClient(\n    token=access_token,\n    token_type='token',\n    base_url='https://api.github.com'\n)\n\n# Simple request with automatic history tracking\nrepos = client.GET('/user/repos')\nprint(f\"Found {len(repos.json())} repositories\")\n\n# Interactive debugging with full context preservation\nresponse = client.GET('/user/repos', params={'per_page': 5}, debug=True)\n# This drops into PDB with complete access to response, session, and request context\n\n# Explore your entire API session interactively\nclient.history_explorer()  # Launches IPython with selectable response history\n```\n\nThis example demonstrates several key benefits: zero-boilerplate setup for common APIs, automatic request history preservation for pattern analysis, embedded debugging that doesn't require separate tooling, and interactive exploration tools that help you understand API behavior through direct investigation.\n\n### Example with custom login method on a subclass\n\nHere's an example for creating test clients on your team's internal platform:\n\n```\nimport webclient_helper as wh\n\n\nclass SomeClient(wh.WebClient):\n    def login(self):\n        headers = {'Content-Type': 'application/json'}\n        data = {'email': self._username, 'password': self._password}\n        response = self.session.post(\n            self._base_url + '/api/login',\n            headers=headers,\n            json=data\n        )\n        self._token = response.json().get('access_token')\n        self._token_type = 'Bearer'\n\n    def get_something(self, params=None, debug=False):\n        return self.GET(\n            '/api/something',\n            params=params,\n            debug=debug\n        )\n\n\nsome_client = SomeClient(\n    username='myuser',\n    password='mypass',\n    base_url='https://somewhere.com',\n)\n\nsomething1 = some_client.get_something(params={'x': 1, 'y': 5})\nsomething2 = some_client.get_something(params={'x': 2, 'y': 10})\n```\n\n## API Overview\n\n### WebClient Class\n\n- **`WebClient(username=None, password=None, token=None, token_type=None, base_url='', user_agent=None, content_type='application/json', extra_headers={})`** - Main HTTP client for conversational API interactions\n  - username: if specified, set auth on session (requires password)\n  - password: if specified, set auth on session (requires username)\n  - token: if specified, use this token in the \"Authorization\" header (requires token_type)\n  - token_type: if specified, use as part of the value in the \"Authorization\" header\n  - base_url: base url for service/API that a subclass would interact with\n  - user_agent: if specified, set \"User-Agent\" header\n  - content_type: content type for requests (defaults to 'application/json')\n  - extra_headers: a dict of extra headers to set on the session\n  - Returns: WebClient instance with session management and authentication handling\n  - Internal calls: `self.set_session()`\n\n- **`WebClient.GET(url, headers=None, params=None, debug=False, retry=False, **kwargs)`** - Send a GET request with automatic history tracking\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - params: a dict with query string vars and values\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.POST(url, headers=None, data=None, json=None, debug=False, retry=False, **kwargs)`** - Send a POST request with data or JSON payload\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - data: a dict to send in the body (non-JSON)\n  - json: a dict to send in the body as JSON\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.PUT(url, headers=None, data=None, debug=False, retry=False, **kwargs)`** - Send a PUT request for resource updates\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - data: a dict to send in the body (non-JSON)\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.PATCH(url, headers=None, data=None, debug=False, retry=False, **kwargs)`** - Send a PATCH request for partial resource updates\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - data: a dict to send in the body (non-JSON)\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.DELETE(url, headers=None, debug=False, retry=False, **kwargs)`** - Send a DELETE request for resource removal\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.OPTIONS(url, headers=None, debug=False, retry=False, **kwargs)`** - Send an OPTIONS request for capability discovery\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.HEAD(url, headers=None, debug=False, retry=False, **kwargs)`** - Send a HEAD request for metadata retrieval\n  - url: url/endpoint (automatically prepends base_url if url starts with '/')\n  - headers: dict of headers to update on the session before making request\n  - debug: if True, enter debugger before returning with full context access\n  - retry: if True and initial response is \"401 Unauthorized\", recreate session and retry\n  - **kwargs: passed to underlying session_method for complete requests library access\n  - Returns: requests.Response object\n  - Internal calls: `wh.session_method()`, `self.set_session()`, `wh.get_summary_from_response()`\n\n- **`WebClient.history_explorer(return_selections=False)`** - Interactive exploration of request history\n  - return_selections: if True, return the selections from history instead of launching IPython\n  - Returns: None by default, or selected history items if return_selections=True\n  - Internal calls: `ih.make_selections()`, `ih.start_ipython()`\n\n- **`WebClient.set_session()`** - Create new session object and invoke login method if defined\n  - Returns: None (modifies self.session in place)\n  - Internal calls: `self.is_login_defined`, `wh.new_requests_session()`, `self.login()`\n\n- **`WebClient.is_login_defined`** (property) - Return True if a login method is defined\n  - Returns: Boolean indicating whether custom login method is implemented\n  - Internal calls: None\n\n### Utility Functions\n\n- **`get_domain(url)`** - Extract domain from URL with www prefix removal\n  - url: URL string to extract domain from\n  - Returns: Domain string with 'www.' prefix removed\n  - Internal calls: None\n\n- **`new_requests_session(username=None, password=None, user_agent=None, content_type=None, extra_headers={})`** - Create new requests Session with authentication and headers\n  - username: if specified, set auth on session (requires password)\n  - password: if specified, set auth on session (requires username)\n  - user_agent: if specified, set \"User-Agent\" header on session\n  - content_type: if specified, set \"Content-Type\" header on session\n  - extra_headers: a dict of extra_headers to set on the session\n  - Returns: configured requests.Session object\n  - Internal calls: None\n\n- **`session_method(method, url, session=None, headers=None, debug=False, **kwargs)`** - Core HTTP request function with debugging support\n  - method: HTTP method (options, head, get, post, put, patch, delete)\n  - url: url/endpoint to request\n  - session: a session object (creates new one if None)\n  - headers: dict of headers to update on the session before making request\n  - debug: if True, enter debugger before returning\n  - **kwargs: additional kwargs that requests.Session.request accepts\n    - params: Dictionary or bytes to be sent in the query string for the Request\n    - data: Dictionary, list of tuples, bytes, or file-like object to send in the body of the Request\n    - json: json to send in the body of the Request\n    - cookies: Dict or CookieJar object to send with the Request\n    - files: Dictionary of 'filename': file-like-objects for multipart encoding upload\n    - auth: Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth\n    - timeout: How long to wait for the server to send data before giving up, as a float, or a (connect timeout, read timeout) tuple\n    - allow_redirects: Set to True by default\n    - proxies: Dictionary mapping protocol or protocol and hostname to the URL of the proxy\n    - stream: whether to immediately download the response content. Defaults to False\n    - verify: Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use. Defaults to True\n    - cert: if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair\n  - Returns: requests.Response object or None if request fails\n  - Internal calls: `new_requests_session()`, `get_summary_from_response()`\n\n- **`get_summary_from_response(response)`** - Generate standardized response summary string\n  - response: requests.Response object to summarize\n  - Returns: String with status code, method, URL, and elapsed time\n  - Internal calls: None\n\n- **`get_soup(url_file_or_string, xml=False, session=None, warn=True)`** - Universal content parser for URLs, files, or strings\n  - url_file_or_string: a string that is either a url to fetch, a file to read, or a string containing HTML/XML content (may also be bytes that are utf-8 encoded)\n  - xml: if True, parse content as XML instead of HTML (requires lxml)\n  - session: a session object for URL fetching\n  - warn: if True, issue a warning if bs4 package is not installed\n  - Returns: BeautifulSoup object or None if BeautifulSoup not available\n  - Internal calls: `session_method()`\n\n- **`download_file(url, localfile='', session=None)`** - Download file with progressive backoff and stream support\n  - url: URL string to download\n  - localfile: local file path (auto-generated if empty)\n  - session: a session object for downloading\n  - Returns: None (downloads file to local filesystem)\n  - Internal calls: `session_method()`, `new_requests_session()`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjyco%2Fwebclient-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenjyco%2Fwebclient-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjyco%2Fwebclient-helper/lists"}