{"id":23418939,"url":"https://github.com/chishui/jssoup","last_synced_at":"2025-05-16T16:07:35.863Z","repository":{"id":21818046,"uuid":"93792022","full_name":"chishui/JSSoup","owner":"chishui","description":"JavaScript + BeautifulSoup = JSSoup","archived":false,"fork":false,"pushed_at":"2023-03-04T02:33:03.000Z","size":268,"stargazers_count":364,"open_issues_count":10,"forks_count":37,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-05-02T04:53:33.385Z","etag":null,"topics":["beautifulsoup","crawler","html","javascript","nodejs","parser","react-native","spider"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chishui.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"patreon":"chishui"}},"created_at":"2017-06-08T21:08:27.000Z","updated_at":"2024-06-18T13:32:40.097Z","dependencies_parsed_at":"2024-06-18T13:32:33.072Z","dependency_job_id":"fd61f89a-e8a9-4585-9933-fdb9149a9b7f","html_url":"https://github.com/chishui/JSSoup","commit_stats":{"total_commits":40,"total_committers":5,"mean_commits":8.0,"dds":"0.19999999999999996","last_synced_commit":"75858e1a395dfa333ba8f11b14b4209d5daa5da7"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chishui%2FJSSoup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chishui%2FJSSoup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chishui%2FJSSoup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chishui%2FJSSoup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chishui","download_url":"https://codeload.github.com/chishui/JSSoup/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586244,"owners_count":21128996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["beautifulsoup","crawler","html","javascript","nodejs","parser","react-native","spider"],"created_at":"2024-12-23T00:46:15.854Z","updated_at":"2025-04-12T14:56:28.382Z","avatar_url":"https://github.com/chishui.png","language":"JavaScript","readme":"JSSoup\n=============================\nI'm a fan of Python library BeautifulSoup. It's feature-rich and very easy to use. But when I am working on a small react-native project, and I tried to find a HTML parser library \nlike BeautifulSoup, I failed.  \nSo I want to write a HTML parser library which can be so easy to use just like BeautifulSoup in Javascript.  \n**JSSoup** uses [tautologistics/node-htmlparser](https://github.com/tautologistics/node-htmlparser) as HTML dom parser, \nand creates a series of BeautifulSoup like API on top of it.  \nJSSoup supports both **node** and **react-native**.  \n\n[![unit-tests](https://github.com/chishui/JSSoup/workflows/unit-tests/badge.svg)](https://github.com/chishui/JSSoup/actions)\n[![npm version](https://badge.fury.io/js/jssoup.svg)](https://badge.fury.io/js/jssoup)\n[![NPM](https://img.shields.io/npm/dm/jssoup.svg)](https://www.npmjs.com/package/jssoup)\n\n\n# Naming Style\nJSSoup tries to use the same interfaces as BeautifulSoup so BeautifulSoup user can use JSSoup seamlessly. \nHowever, JSSoup uses Javascript's camelCase naming style instead of Python's underscore naming style.\nSuch as `find_all()` in BeautifulSoup is replaced as `findAll()`.\n\n# Install\n```\n$ npm install jssoup \n```\n\n# How to use JSSoup\n## Import\n```javascript\n//react-native\nimport JSSoup from 'jssoup'; \n// nodejs\nvar JSSoup = require('jssoup').default;\n```\n## Make Soup\n```javascript\nvar soup = new JSSoup('\u003chtml\u003e\u003chead\u003ehello\u003c/head\u003e\u003c/html\u003e');\n```\n\u003e The text element only contains whitespace will be ignored by default. To disable this feature, set second parameter \nof JSSoup to false. This parameter is \"ignoreWhitespace\" and will be passed into htmlparser.\n```javascript\nvar soup = new JSSoup('\u003chtml\u003e\u003chead\u003ehello\u003c/head\u003e\u003c/html\u003e', false);\n```\n## Access Element Attributes\n### Name\n```javascript\nvar soup = new JSSoup('\u003chtml\u003e\u003chead\u003ehello\u003c/head\u003e\u003c/html\u003e');\nvar tag = soup.find('head');\ntag.name\n// 'head'\ntag.name = 'span'\nconsole.log(tag)\n//\u003cspan\u003ehello\u003c/span\u003e\n```\n### Attributes\n```javascript\nvar soup = new JSSoup('\u003ctag id=\"hi\" class=\"banner\"\u003ehello\u003c/tag\u003e');\nvar tag = soup.nextElement;\ntag.attrs\n// {id: 'hi', class: 'banner'} \ntag.attrs.id = 'test';\nconsole.log(tag)\n// \u003ctag id=\"test\" class=\"banner\"\u003ehello\u003c/tag\u003e\n```\n\n## Navigation\n### .previousElement, .nextElement\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003ca\u003e1\u003c/a\u003e\n  \u003cb\u003e2\u003c/b\u003e\n  \u003cc\u003e3\u003c/c\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar div = soup.nextElement;\nvar b = div.nextElement.nextElement;\n// b.string: '2'\nvar a = b.previousElement;\n// a.string: '1'\n```\n### .previousSibling, .nextSibling\n```javascript\nvar soup = new JSSoup(data);\nvar div = soup.nextElement;\nvar a = div.nextElement;\nvar b = a.nextSibling;\nvar c = b.nextSibling;\nc.nextSibling == undefined;\n```\n### .previousSiblings, .nextSiblings\n```javascript\nvar soup = new JSSoup(data);\nvar a = soup.find(\"a\");\na.nextSiblings\n// [\u003cb\u003e2\u003c/b\u003e, \u003cc\u003e3\u003c/c\u003e]\nvar c = soup.find(\"c\");\nc.previousSiblings\n// [\u003ca\u003e1\u003c/a\u003e, \u003cb\u003e2\u003c/b\u003e]\n```\n### .contents\n`.contents` contains direct children of current element.\n```javascript\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cb\u003e2\u003c/b\u003e, \u003cc\u003e3\u003c/c\u003e]\n```\n### .descendants\n`.descendants` includes all elements of which current element is the ancestor of.\n```javascript\ndiv.descendants\n// [\u003ca\u003e1\u003c/a\u003e, 1, \u003cb\u003e2\u003c/b\u003e, 2, \u003cc\u003e3\u003c/c\u003e, 3]\n```\n### .parent\n```javascript\ndiv.parent == soup\n```\n## Edit\n### .extract()\n```javascript\nb.extract();\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cc\u003e3\u003c/c\u003e]\n```\n### .append()\n```javascript\nb.extract();\ndiv.append(b)\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cc\u003e3\u003c/c\u003e, \u003cb\u003e2\u003c/b\u003e]\n```\n### .insert(position, new Element)\n```javascript\nd.prettify('', '')\n// \u003cd\u003e4\u003c/d\u003e\ndiv.insert(1, d)\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cd\u003e4\u003c/d\u003e, \u003cb\u003e2\u003c/b\u003e, \u003cc\u003e3\u003c/c\u003e]\n```\n### .replaceWith(new Element)\n```javascript\nd.prettify('', '')\n// \u003cd\u003e4\u003c/d\u003e\nb.replaceWith(d)\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cd\u003e4\u003c/d\u003e, \u003cc\u003e3\u003c/c\u003e]\n\nc.string.replaceWith('new')\ndiv.contents\n// [\u003ca\u003e1\u003c/a\u003e, \u003cd\u003e4\u003c/d\u003e, \u003cc\u003enew\u003c/c\u003e]\n```\n\n## Search\n### .findAll()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cdiv class=\"h1\"\u003e\u003c/div\u003e\n  \u003ca\u003ehello\u003c/a\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nsoup.findAll('a')\n// [\u003ca\u003ehello\u003c/a\u003e]\nsoup.findAll('div', 'h1')\n// [\u003cdiv class=\"h1\"\u003e\u003c/div\u003e]\n```\n### .find()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cp\u003e hello \u003c/p\u003e\n  \u003cp\u003e world \u003c/p\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nsoup.find('p')\n// \u003cp\u003e hello \u003c/p\u003e\n```\n### .findNextSibling()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n  \u003cdiv\u003e div \u003c/div\u003e\n  \u003cp\u003e hello \u003c/p\u003e\n  \u003cp\u003e world \u003c/p\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar span = soup.find('span');\nspan.findNextSibling('p')\n// \u003cp\u003e hello \u003c/p\u003e\n```\n### .findNextSiblings()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n  \u003cdiv\u003e div \u003c/div\u003e\n  \u003cp\u003e hello \u003c/p\u003e\n  \u003cp\u003e world \u003c/p\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar span = soup.find('span');\nspan.findNextSiblings('p')\n// \u003cp\u003e hello \u003c/p\u003e\n// \u003cp\u003e world \u003c/p\u003e\n```\n### .findPreviousSibling()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cp\u003e hello \u003c/p\u003e\n  \u003cp\u003e world \u003c/p\u003e\n  \u003cdiv\u003e div \u003c/div\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar span = soup.find('span');\nspan.findPreviousSibling('p')\n// \u003cp\u003e world \u003c/p\u003e\n```\n### .findPreviousSiblings()\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cp\u003e hello \u003c/p\u003e\n  \u003cp\u003e world \u003c/p\u003e\n  \u003cdiv\u003e div \u003c/div\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar span = soup.find('span');\nspan.findPreviousSiblings('p')\n// \u003cp\u003e hello \u003c/p\u003e\n// \u003cp\u003e world \u003c/p\u003e\n```\n## CSS Selector\nJSSoup utilizes [JSSoupSelector](https://github.com/chishui/JSSoupSelector) for CSS selector functionalities.\n### .select\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cp class=\"class1\" id=\"id1\"\u003e hello \u003c/p\u003e\n  \u003cp id=\"id2\"\u003e world \u003c/p\u003e\n  \u003cdiv class=\"class1\"\u003e div \u003c/div\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar elements = soup.select('div \u003e .class1');\nelements\n// [ \u003cp class=\"class1\" id=\"id1\"\u003e hello \u003c/p\u003e, \u003cdiv class=\"class1\"\u003e div \u003c/div\u003e]\n```\n### .selectOne\n```javascript\nvar data = `\n\u003cdiv\u003e\n  \u003cp class=\"class1\" id=\"id1\"\u003e hello \u003c/p\u003e\n  \u003cp id=\"id2\"\u003e world \u003c/p\u003e\n  \u003cdiv class=\"class1\"\u003e div \u003c/div\u003e\n  \u003cspan\u003e test \u003c/span\u003e\n\u003c/div\u003e\n`\nvar soup = new JSSoup(data);\nvar element = soup.selectOne('div \u003e p#id1');\nelement\n// \u003cp class=\"class1\" id=\"id1\"\u003e hello \u003c/p\u003e\n```\n## Output\n### .prettify()\n```javascript\nvar soup = new JSSoup('\u003chtml\u003e\u003chead\u003ehello\u003c/head\u003e\u003c/html\u003e');\nsoup.prettify()\n// \u003chtml\u003e\n//  \u003chead\u003e\n//   hello\n//  \u003c/head\u003e\n// \u003c/html\u003e\n```\n### .getText(), .text\n```javascript\ndiv.text\n// '123'\ndiv.getText('|')\n// '1|2|3'\n```\n### .string\n```javascript\nb.string == '2';\nvar soup = new JSSoup('\u003chtml\u003e\u003chead\u003ehello\u003c/head\u003e\u003c/html\u003e');\nsoup.string == 'hello';\n```\n\n# Run Test\n```\nnpm test\n```\n\n","funding_links":["https://patreon.com/chishui"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchishui%2Fjssoup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchishui%2Fjssoup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchishui%2Fjssoup/lists"}