+
+
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart
## How to use
From 3438bccb036d122e1255eaf9dc6fcd4f4cc493e1 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:31:24 +0530
Subject: [PATCH 03/45] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 446f442..28fea44 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
Amazon-Flipkart Price Comparison Engine
+
@@ -13,7 +13,7 @@
-
+
Amazon-Flipkart Price Comparison Engine
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart
From 4b24d0e26e453ba3315a892420cf4539d54c74b4 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:33:46 +0530
Subject: [PATCH 04/45] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 28fea44..70a9931 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
Amazon-Flipkart Price Comparison Engine
-Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart
+
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
## How to use
After running this program a window is popped up which asks user to enter the product
From ff651f65720833778d6bf49e2ef50aa95e7f71e3 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:34:57 +0530
Subject: [PATCH 05/45] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 70a9931..802acba 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,9 @@
Amazon-Flipkart Price Comparison Engine
-
-
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
+
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
+
## How to use
After running this program a window is popped up which asks user to enter the product
From 3b16ce794283c7eacb3f570ea74b50ea03f2a842 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:36:19 +0530
Subject: [PATCH 06/45] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 802acba..25cfc58 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
+
Amazon-Flipkart Price Comparison Engine
@@ -13,7 +13,7 @@
-
Amazon-Flipkart Price Comparison Engine
+
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
+
+
+
## How to use
After running this program a window is popped up which asks user to enter the product
From a1a98760b5fab2666726cd94b99947b1941c1ccd Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:38:40 +0530
Subject: [PATCH 08/45] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f428179..8ba340f 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@
## How to use
After running this program a window is popped up which asks user to enter the product
-![screenshot 5](https://user-images.githubusercontent.com/40419750/42380586-114b5d8e-814c-11e8-9147-e24ad9a309a6.png)
+
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices
From d4fead3c0ee3519bbc925028ffa8397cc9deedd8 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:40:33 +0530
Subject: [PATCH 09/45] Update README.md
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 8ba340f..d8aab15 100644
--- a/README.md
+++ b/README.md
@@ -22,9 +22,9 @@
## How to use
After running this program a window is popped up which asks user to enter the product
-
-
-
+
+
+
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices
![screenshot 6](https://user-images.githubusercontent.com/40419750/42381017-687b5cfc-814d-11e8-9312-8a46054e5286.png)
From 88fc24c77b3d394637578f7791dd380fbc4c2522 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:44:18 +0530
Subject: [PATCH 10/45] Update README.md
---
README.md | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index d8aab15..03289af 100644
--- a/README.md
+++ b/README.md
@@ -21,17 +21,21 @@
## How to use
-After running this program a window is popped up which asks user to enter the product
+
After running this program a window is popped up which asks user to enter the product.
-After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices
-![screenshot 6](https://user-images.githubusercontent.com/40419750/42381017-687b5cfc-814d-11e8-9312-8a46054e5286.png)
+
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices.
-If you didn't get the desired product then click on the title to get suggestions related to your search
+
If you didn't get the desired product then click on the title to get suggestions related to your search.
+
+
+
Select the desired product from the suggestions for both sites and then click on the 'Search' button to get their corresponding prices
From 8e7077741785c62d5644dbd10f14d3b179c9be79 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:46:34 +0530
Subject: [PATCH 11/45] Update README.md
---
README.md | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 03289af..d2b4851 100644
--- a/README.md
+++ b/README.md
@@ -21,25 +21,26 @@
## How to use
-
After running this program a window is popped up which asks user to enter the product.
+
After running this program a window is popped up which asks user to enter the product.
-
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices.
+
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices.
-
If you didn't get the desired product then click on the title to get suggestions related to your search.
+
If you didn't get the desired product then click on the title to get suggestions related to your search.
-Select the desired product from the suggestions for both sites and then click on the 'Search' button to get their corresponding prices
-
-![screenshot 9](https://user-images.githubusercontent.com/40419750/42381782-cbcb1bd8-814f-11e8-92c2-245ed3f2dc5d.png)
+
Select the desired product from the suggestions for both sites and then click on the 'Search' button to get their corresponding prices.
+
+
+
## Highlights:
1. You can try out suggestions to find other products related to your search just by clicking on the title of the product.
From 4eedb1a21d0d1a5fa2db5a96784bcfd503997969 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 18:48:23 +0530
Subject: [PATCH 12/45] Update README.md
---
README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index d2b4851..3114ea7 100644
--- a/README.md
+++ b/README.md
@@ -21,23 +21,23 @@
## How to use
-
After running this program a window is popped up which asks user to enter the product.
+
After running this program a window is popped up which asks user to enter the product.
-
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices.
+
After entering the product and clicking on the 'Find' button it will take us to another window which will show the title of the product on both sites and there corresponding prices.
-
If you didn't get the desired product then click on the title to get suggestions related to your search.
+
If you didn't get the desired product then click on the title to get suggestions related to your search.
-
+
-
Select the desired product from the suggestions for both sites and then click on the 'Search' button to get their corresponding prices.
+
Select the desired product from the suggestions for both sites and then click on the 'Search' button to get their corresponding prices.
From 3d64ba98f133d0058a386eab2719a7cfbae5b221 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 19:22:09 +0530
Subject: [PATCH 13/45] Update README.md
---
README.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/README.md b/README.md
index 3114ea7..e3b8c6a 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,11 @@ To avoid 'Product not found', try searching the basic model and then select the
For Example: Instead of searching 'Apple iPhone X (Space Grey, 256GB)', search 'Apple iPhone X' and then select the desired specifications from suggestions.
+
+
+## Future Scope:
+Currently this program works only on two e-commerce sites. More websites can be added to it. If you have more ideas, I'm excited to view Pull Requests from your side!
+
For more information, visit my website
From eeca6d6b9f37d1f5d1d32adc07f81a09b1518a8d Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 19:22:51 +0530
Subject: [PATCH 14/45] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e3b8c6a..b9aa530 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ For Example: Instead of searching 'Apple iPhone X (Space Grey, 256GB)', search '
## Future Scope:
Currently this program works only on two e-commerce sites. More websites can be added to it. If you have more ideas, I'm excited to view Pull Requests from your side!
-For more information, visit my website
+For more information, visit my website.
From 1797818750ecb0ce770c18482dcf6c52d655b251 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 19:24:39 +0530
Subject: [PATCH 15/45] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index b9aa530..9bd1e36 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ For Example: Instead of searching 'Apple iPhone X (Space Grey, 256GB)', search '
## Future Scope:
Currently this program works only on two e-commerce sites. More websites can be added to it. If you have more ideas, I'm excited to view Pull Requests from your side!
-For more information, visit my website.
+For more information, you can visit my website.
From 95c486e62407eccc00d676faf2099bd0904389bd Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 20:02:14 +0530
Subject: [PATCH 16/45] Create FUNDING.yml
---
.github/FUNDING.yml | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..4b16f59
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
From 5d8257c88358a0f244a0a8bdcd2af795f10ee622 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 4 Aug 2019 20:03:13 +0530
Subject: [PATCH 17/45] Delete FUNDING.yml
---
.github/FUNDING.yml | 12 ------------
1 file changed, 12 deletions(-)
delete mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 4b16f59..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
From 653dce75fedfa8910f1bfa0410d4965ce340a4ac Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Tue, 6 Aug 2019 19:12:18 +0530
Subject: [PATCH 18/45] Rename Price comparison engine.py to
Price_comparison_engine.py
---
Price comparison engine.py => Price_comparison_engine.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Price comparison engine.py => Price_comparison_engine.py (100%)
diff --git a/Price comparison engine.py b/Price_comparison_engine.py
similarity index 100%
rename from Price comparison engine.py
rename to Price_comparison_engine.py
From 497054341336489d3eeb60bd64d7a72440e2d744 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Tue, 6 Aug 2019 19:16:36 +0530
Subject: [PATCH 19/45] Rename Price_comparison_engine.py to
price_comparison_engine.py
---
Price_comparison_engine.py => price_comparison_engine.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Price_comparison_engine.py => price_comparison_engine.py (100%)
diff --git a/Price_comparison_engine.py b/price_comparison_engine.py
similarity index 100%
rename from Price_comparison_engine.py
rename to price_comparison_engine.py
From 7d3c01d1e12d9cfd922332ee26f8c35198faf806 Mon Sep 17 00:00:00 2001
From: Sushant Patrikar
Date: Sun, 27 Oct 2019 00:39:17 +0530
Subject: [PATCH 20/45] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 9bd1e36..ff8bb33 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
-
Compares price of the product entered by an user from e-commerce sites Amazon and Flipkart.
+
Compares price of the product entered by the user from e-commerce sites Amazon and Flipkart.
+
+
+>>> soup.find(text="bad")
+u'bad'
+>>> soup.i
+HTML
+#
+>>> soup = BeautifulSoup("SomebadXML", "xml")
+#
+>>> print soup.prettify()
+
+
+Some
+
+bad
+
+XML
+
+
+```
+
+To go beyond the basics, [comprehensive documentation is available](http://www.crummy.com/software/BeautifulSoup/bs4/doc/).
+
+# Links
+
+* [Homepage](http://www.crummy.com/software/BeautifulSoup/bs4/)
+* [Documentation](http://www.crummy.com/software/BeautifulSoup/bs4/doc/)
+* [Discussion group](http://groups.google.com/group/beautifulsoup/)
+* [Development](https://code.launchpad.net/beautifulsoup/)
+* [Bug tracker](https://bugs.launchpad.net/beautifulsoup/)
+* [Complete changelog](https://bazaar.launchpad.net/~leonardr/beautifulsoup/bs4/view/head:/CHANGELOG)
+
+# Note on Python 2 sunsetting
+
+Since 2012, Beautiful Soup has been developed as a Python 2 library
+which is automatically converted to Python 3 code as necessary. This
+makes it impossible to take advantage of some features of Python
+3.
+
+For this reason, I plan to discontinue Beautiful Soup's Python 2
+support at some point after December 31, 2020: one year after the
+sunset date for Python 2 itself. Beyond that point, new Beautiful Soup
+development will exclusively target Python 3. Of course, older
+releases of Beautiful Soup, which support both versions, will continue
+to be available.
+
+# Supporting the project
+
+If you use Beautiful Soup as part of your professional work, please consider a
+[Tidelift subscription](https://tidelift.com/subscription/pkg/pypi-beautifulsoup4?utm_source=pypi-beautifulsoup4&utm_medium=referral&utm_campaign=readme).
+This will support many of the free software projects your organization
+depends on, not just Beautiful Soup.
+
+If you use Beautiful Soup for personal projects, the best way to say
+thank you is to read
+[Tool Safety](https://www.crummy.com/software/BeautifulSoup/zine/), a zine I
+wrote about what Beautiful Soup has taught me about software
+development.
+
+# Building the documentation
+
+The bs4/doc/ directory contains full documentation in Sphinx
+format. Run `make html` in that directory to create HTML
+documentation.
+
+# Running the unit tests
+
+Beautiful Soup supports unit test discovery from the project root directory:
+
+```
+$ nosetests
+```
+
+```
+$ python -m unittest discover -s bs4
+```
+
+If you checked out the source tree, you should see a script in the
+home directory called test-all-versions. This script will run the unit
+tests under Python 2, then create a temporary Python 3 conversion of
+the source and run the unit tests again under Python 3.
+
+
diff --git a/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/RECORD b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/RECORD
new file mode 100644
index 0000000..fa583fc
--- /dev/null
+++ b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/RECORD
@@ -0,0 +1,44 @@
+beautifulsoup4-4.9.1.dist-info/AUTHORS,sha256=uSIdbrBb1sobdXl7VrlUvuvim2dN9kF3MH4Edn0WKGE,2176
+beautifulsoup4-4.9.1.dist-info/COPYING.txt,sha256=pH6lEjYJhGT-C09Vl0NZC1MwVtngD0nsv4Apn6tH4jE,1315
+beautifulsoup4-4.9.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+beautifulsoup4-4.9.1.dist-info/LICENSE,sha256=ynIn3bnu1syAnhV_Z7Ag543eBjJAAB0RhW-FxJy25CM,1447
+beautifulsoup4-4.9.1.dist-info/METADATA,sha256=cIvKNOIcfpYqN5nITv3UDCtXZF1l_B5cPwpib-Gkjk8,4062
+beautifulsoup4-4.9.1.dist-info/RECORD,,
+beautifulsoup4-4.9.1.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
+beautifulsoup4-4.9.1.dist-info/top_level.txt,sha256=H8VT-IuPWLzQqwG9_eChjXDJ1z0H9RRebdSR90Bjnkw,4
+bs4/__init__.py,sha256=ZM_Revj0Yipo_FRYdxS-rksn3MFXzR3XRyFirnM-h84,31551
+bs4/__pycache__/__init__.cpython-36.pyc,,
+bs4/__pycache__/dammit.cpython-36.pyc,,
+bs4/__pycache__/diagnose.cpython-36.pyc,,
+bs4/__pycache__/element.cpython-36.pyc,,
+bs4/__pycache__/formatter.cpython-36.pyc,,
+bs4/__pycache__/testing.cpython-36.pyc,,
+bs4/builder/__init__.py,sha256=VgrBobApHGLnuA8VCJuumZDP64UiGEzlxJJgLiV--sU,19841
+bs4/builder/__pycache__/__init__.cpython-36.pyc,,
+bs4/builder/__pycache__/_html5lib.cpython-36.pyc,,
+bs4/builder/__pycache__/_htmlparser.cpython-36.pyc,,
+bs4/builder/__pycache__/_lxml.cpython-36.pyc,,
+bs4/builder/_html5lib.py,sha256=hDxlzVrAku_eU7zEt4gZ-sAXzG58GvkLfMz6P4zUqoA,18748
+bs4/builder/_htmlparser.py,sha256=PEKGvBcJcf6_78CVwA1_uLxulnmnlRuWH0W2caTzpKk,18406
+bs4/builder/_lxml.py,sha256=e4w91RZi3NII_QYe2e1-EiN_BxQtgJPSRwQ8Xgz41ZA,12234
+bs4/dammit.py,sha256=k_XPB3kbZsHM01ckf9BxCUB2Eu2dIQ3d3DDt7UEv9RA,34130
+bs4/diagnose.py,sha256=HkiiFUWS9KU3sLILDYm8X-Tu0wZRuTdMClqtXPd99go,7761
+bs4/element.py,sha256=N6UNaAICZ0BjUl2VnZWZJz7b-v9W50R1YrCmaZbXw_0,81066
+bs4/formatter.py,sha256=Wayv1d6fUc9BSCa2k9uhvWwm89xCukdtJhyi9Sxvkuc,5654
+bs4/testing.py,sha256=xpDhC4AQaVrvNVog1Lgg8nUtg0Nack0CyEVD-bjAAj0,44897
+bs4/tests/__init__.py,sha256=bdUBDE750n7qNEfue7-3a1fBaUxJlvZMkvJvZa-lbYs,27
+bs4/tests/__pycache__/__init__.cpython-36.pyc,,
+bs4/tests/__pycache__/test_builder_registry.cpython-36.pyc,,
+bs4/tests/__pycache__/test_docs.cpython-36.pyc,,
+bs4/tests/__pycache__/test_html5lib.cpython-36.pyc,,
+bs4/tests/__pycache__/test_htmlparser.cpython-36.pyc,,
+bs4/tests/__pycache__/test_lxml.cpython-36.pyc,,
+bs4/tests/__pycache__/test_soup.cpython-36.pyc,,
+bs4/tests/__pycache__/test_tree.cpython-36.pyc,,
+bs4/tests/test_builder_registry.py,sha256=pllfRpArh9TYhjjRUiu1wITr9Ryyv4hiaAtRjij-k4E,5582
+bs4/tests/test_docs.py,sha256=FXfz2bGL4Xe0q6duwpmg9hmFiZuU4DVJPNZ0hTb6aH4,1067
+bs4/tests/test_html5lib.py,sha256=eWnLGHek_RO_TMq0Ixpb1RF3BEDrvhenMf2eaEBjjsg,6754
+bs4/tests/test_htmlparser.py,sha256=3294XvFbWVe0AYoTlnLPEDW_a0Om0BKRcsrwlJbxUaI,3941
+bs4/tests/test_lxml.py,sha256=xJr8eDrtHSb_vQw88lYEKyfdM1Hel4-dBaz14vQq78M,4105
+bs4/tests/test_soup.py,sha256=EhE1dhHKyctNu0y2l0ql6FOHg9qliEt8Kh7jfCx1lDw,29303
+bs4/tests/test_tree.py,sha256=W75j1-aDx8qHWzOr_JtRCjDE83nUShFauEzGfoys2k0,88988
diff --git a/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/WHEEL b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/WHEEL
new file mode 100644
index 0000000..b552003
--- /dev/null
+++ b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.34.2)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/top_level.txt b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/top_level.txt
new file mode 100644
index 0000000..1315442
--- /dev/null
+++ b/venv/Lib/site-packages/beautifulsoup4-4.9.1.dist-info/top_level.txt
@@ -0,0 +1 @@
+bs4
diff --git a/venv/Lib/site-packages/bs4/__init__.py b/venv/Lib/site-packages/bs4/__init__.py
new file mode 100644
index 0000000..afaca71
--- /dev/null
+++ b/venv/Lib/site-packages/bs4/__init__.py
@@ -0,0 +1,777 @@
+"""Beautiful Soup Elixir and Tonic - "The Screen-Scraper's Friend".
+
+http://www.crummy.com/software/BeautifulSoup/
+
+Beautiful Soup uses a pluggable XML or HTML parser to parse a
+(possibly invalid) document into a tree representation. Beautiful Soup
+provides methods and Pythonic idioms that make it easy to navigate,
+search, and modify the parse tree.
+
+Beautiful Soup works with Python 2.7 and up. It works better if lxml
+and/or html5lib is installed.
+
+For more than you ever wanted to know about Beautiful Soup, see the
+documentation: http://www.crummy.com/software/BeautifulSoup/bs4/doc/
+"""
+
+__author__ = "Leonard Richardson (leonardr@segfault.org)"
+__version__ = "4.9.1"
+__copyright__ = "Copyright (c) 2004-2020 Leonard Richardson"
+# Use of this source code is governed by the MIT license.
+__license__ = "MIT"
+
+__all__ = ['BeautifulSoup']
+
+import os
+import re
+import sys
+import traceback
+import warnings
+
+from .builder import builder_registry, ParserRejectedMarkup
+from .dammit import UnicodeDammit
+from .element import (
+ CData,
+ Comment,
+ DEFAULT_OUTPUT_ENCODING,
+ Declaration,
+ Doctype,
+ NavigableString,
+ PageElement,
+ ProcessingInstruction,
+ PYTHON_SPECIFIC_ENCODINGS,
+ ResultSet,
+ Script,
+ Stylesheet,
+ SoupStrainer,
+ Tag,
+ TemplateString,
+ )
+
+# The very first thing we do is give a useful error if someone is
+# running this code under Python 3 without converting it.
+'You are trying to run the Python 2 version of Beautiful Soup under Python 3. This will not work.'!='You need to convert the code, either by installing it (`python setup.py install`) or by running 2to3 (`2to3 -w bs4`).'
+
+# Define some custom warnings.
+class GuessedAtParserWarning(UserWarning):
+ """The warning issued when BeautifulSoup has to guess what parser to
+ use -- probably because no parser was specified in the constructor.
+ """
+
+class MarkupResemblesLocatorWarning(UserWarning):
+ """The warning issued when BeautifulSoup is given 'markup' that
+ actually looks like a resource locator -- a URL or a path to a file
+ on disk.
+ """
+
+
+class BeautifulSoup(Tag):
+ """A data structure representing a parsed HTML or XML document.
+
+ Most of the methods you'll call on a BeautifulSoup object are inherited from
+ PageElement or Tag.
+
+ Internally, this class defines the basic interface called by the
+ tree builders when converting an HTML/XML document into a data
+ structure. The interface abstracts away the differences between
+ parsers. To write a new tree builder, you'll need to understand
+ these methods as a whole.
+
+ These methods will be called by the BeautifulSoup constructor:
+ * reset()
+ * feed(markup)
+
+ The tree builder may call these methods from its feed() implementation:
+ * handle_starttag(name, attrs) # See note about return value
+ * handle_endtag(name)
+ * handle_data(data) # Appends to the current data node
+ * endData(containerClass) # Ends the current data node
+
+ No matter how complicated the underlying parser is, you should be
+ able to build a tree using 'start tag' events, 'end tag' events,
+ 'data' events, and "done with data" events.
+
+ If you encounter an empty-element tag (aka a self-closing tag,
+ like HTML's tag), call handle_starttag and then
+ handle_endtag.
+ """
+
+ # Since BeautifulSoup subclasses Tag, it's possible to treat it as
+ # a Tag with a .name. This name makes it clear the BeautifulSoup
+ # object isn't a real markup tag.
+ ROOT_TAG_NAME = '[document]'
+
+ # If the end-user gives no indication which tree builder they
+ # want, look for one with these features.
+ DEFAULT_BUILDER_FEATURES = ['html', 'fast']
+
+ # A string containing all ASCII whitespace characters, used in
+ # endData() to detect data chunks that seem 'empty'.
+ ASCII_SPACES = '\x20\x0a\x09\x0c\x0d'
+
+ NO_PARSER_SPECIFIED_WARNING = "No parser was explicitly specified, so I'm using the best available %(markup_type)s parser for this system (\"%(parser)s\"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.\n\nThe code that caused this warning is on line %(line_number)s of the file %(filename)s. To get rid of this warning, pass the additional argument 'features=\"%(parser)s\"' to the BeautifulSoup constructor.\n"
+
+ def __init__(self, markup="", features=None, builder=None,
+ parse_only=None, from_encoding=None, exclude_encodings=None,
+ element_classes=None, **kwargs):
+ """Constructor.
+
+ :param markup: A string or a file-like object representing
+ markup to be parsed.
+
+ :param features: Desirable features of the parser to be
+ used. This may be the name of a specific parser ("lxml",
+ "lxml-xml", "html.parser", or "html5lib") or it may be the
+ type of markup to be used ("html", "html5", "xml"). It's
+ recommended that you name a specific parser, so that
+ Beautiful Soup gives you the same results across platforms
+ and virtual environments.
+
+ :param builder: A TreeBuilder subclass to instantiate (or
+ instance to use) instead of looking one up based on
+ `features`. You only need to use this if you've implemented a
+ custom TreeBuilder.
+
+ :param parse_only: A SoupStrainer. Only parts of the document
+ matching the SoupStrainer will be considered. This is useful
+ when parsing part of a document that would otherwise be too
+ large to fit into memory.
+
+ :param from_encoding: A string indicating the encoding of the
+ document to be parsed. Pass this in if Beautiful Soup is
+ guessing wrongly about the document's encoding.
+
+ :param exclude_encodings: A list of strings indicating
+ encodings known to be wrong. Pass this in if you don't know
+ the document's encoding but you know Beautiful Soup's guess is
+ wrong.
+
+ :param element_classes: A dictionary mapping BeautifulSoup
+ classes like Tag and NavigableString, to other classes you'd
+ like to be instantiated instead as the parse tree is
+ built. This is useful for subclassing Tag or NavigableString
+ to modify default behavior.
+
+ :param kwargs: For backwards compatibility purposes, the
+ constructor accepts certain keyword arguments used in
+ Beautiful Soup 3. None of these arguments do anything in
+ Beautiful Soup 4; they will result in a warning and then be
+ ignored.
+
+ Apart from this, any keyword arguments passed into the
+ BeautifulSoup constructor are propagated to the TreeBuilder
+ constructor. This makes it possible to configure a
+ TreeBuilder by passing in arguments, not just by saying which
+ one to use.
+ """
+ if 'convertEntities' in kwargs:
+ del kwargs['convertEntities']
+ warnings.warn(
+ "BS4 does not respect the convertEntities argument to the "
+ "BeautifulSoup constructor. Entities are always converted "
+ "to Unicode characters.")
+
+ if 'markupMassage' in kwargs:
+ del kwargs['markupMassage']
+ warnings.warn(
+ "BS4 does not respect the markupMassage argument to the "
+ "BeautifulSoup constructor. The tree builder is responsible "
+ "for any necessary markup massage.")
+
+ if 'smartQuotesTo' in kwargs:
+ del kwargs['smartQuotesTo']
+ warnings.warn(
+ "BS4 does not respect the smartQuotesTo argument to the "
+ "BeautifulSoup constructor. Smart quotes are always converted "
+ "to Unicode characters.")
+
+ if 'selfClosingTags' in kwargs:
+ del kwargs['selfClosingTags']
+ warnings.warn(
+ "BS4 does not respect the selfClosingTags argument to the "
+ "BeautifulSoup constructor. The tree builder is responsible "
+ "for understanding self-closing tags.")
+
+ if 'isHTML' in kwargs:
+ del kwargs['isHTML']
+ warnings.warn(
+ "BS4 does not respect the isHTML argument to the "
+ "BeautifulSoup constructor. Suggest you use "
+ "features='lxml' for HTML and features='lxml-xml' for "
+ "XML.")
+
+ def deprecated_argument(old_name, new_name):
+ if old_name in kwargs:
+ warnings.warn(
+ 'The "%s" argument to the BeautifulSoup constructor '
+ 'has been renamed to "%s."' % (old_name, new_name))
+ value = kwargs[old_name]
+ del kwargs[old_name]
+ return value
+ return None
+
+ parse_only = parse_only or deprecated_argument(
+ "parseOnlyThese", "parse_only")
+
+ from_encoding = from_encoding or deprecated_argument(
+ "fromEncoding", "from_encoding")
+
+ if from_encoding and isinstance(markup, str):
+ warnings.warn("You provided Unicode markup but also provided a value for from_encoding. Your from_encoding will be ignored.")
+ from_encoding = None
+
+ self.element_classes = element_classes or dict()
+
+ # We need this information to track whether or not the builder
+ # was specified well enough that we can omit the 'you need to
+ # specify a parser' warning.
+ original_builder = builder
+ original_features = features
+
+ if isinstance(builder, type):
+ # A builder class was passed in; it needs to be instantiated.
+ builder_class = builder
+ builder = None
+ elif builder is None:
+ if isinstance(features, str):
+ features = [features]
+ if features is None or len(features) == 0:
+ features = self.DEFAULT_BUILDER_FEATURES
+ builder_class = builder_registry.lookup(*features)
+ if builder_class is None:
+ raise FeatureNotFound(
+ "Couldn't find a tree builder with the features you "
+ "requested: %s. Do you need to install a parser library?"
+ % ",".join(features))
+
+ # At this point either we have a TreeBuilder instance in
+ # builder, or we have a builder_class that we can instantiate
+ # with the remaining **kwargs.
+ if builder is None:
+ builder = builder_class(**kwargs)
+ if not original_builder and not (
+ original_features == builder.NAME or
+ original_features in builder.ALTERNATE_NAMES
+ ):
+ if builder.is_xml:
+ markup_type = "XML"
+ else:
+ markup_type = "HTML"
+
+ # This code adapted from warnings.py so that we get the same line
+ # of code as our warnings.warn() call gets, even if the answer is wrong
+ # (as it may be in a multithreading situation).
+ caller = None
+ try:
+ caller = sys._getframe(1)
+ except ValueError:
+ pass
+ if caller:
+ globals = caller.f_globals
+ line_number = caller.f_lineno
+ else:
+ globals = sys.__dict__
+ line_number= 1
+ filename = globals.get('__file__')
+ if filename:
+ fnl = filename.lower()
+ if fnl.endswith((".pyc", ".pyo")):
+ filename = filename[:-1]
+ if filename:
+ # If there is no filename at all, the user is most likely in a REPL,
+ # and the warning is not necessary.
+ values = dict(
+ filename=filename,
+ line_number=line_number,
+ parser=builder.NAME,
+ markup_type=markup_type
+ )
+ warnings.warn(
+ self.NO_PARSER_SPECIFIED_WARNING % values,
+ GuessedAtParserWarning, stacklevel=2
+ )
+ else:
+ if kwargs:
+ warnings.warn("Keyword arguments to the BeautifulSoup constructor will be ignored. These would normally be passed into the TreeBuilder constructor, but a TreeBuilder instance was passed in as `builder`.")
+
+ self.builder = builder
+ self.is_xml = builder.is_xml
+ self.known_xml = self.is_xml
+ self._namespaces = dict()
+ self.parse_only = parse_only
+
+ self.builder.initialize_soup(self)
+
+ if hasattr(markup, 'read'): # It's a file-type object.
+ markup = markup.read()
+ elif len(markup) <= 256 and (
+ (isinstance(markup, bytes) and not b'<' in markup)
+ or (isinstance(markup, str) and not '<' in markup)
+ ):
+ # Print out warnings for a couple beginner problems
+ # involving passing non-markup to Beautiful Soup.
+ # Beautiful Soup will still parse the input as markup,
+ # just in case that's what the user really wants.
+ if (isinstance(markup, str)
+ and not os.path.supports_unicode_filenames):
+ possible_filename = markup.encode("utf8")
+ else:
+ possible_filename = markup
+ is_file = False
+ try:
+ is_file = os.path.exists(possible_filename)
+ except Exception as e:
+ # This is almost certainly a problem involving
+ # characters not valid in filenames on this
+ # system. Just let it go.
+ pass
+ if is_file:
+ warnings.warn(
+ '"%s" looks like a filename, not markup. You should'
+ ' probably open this file and pass the filehandle into'
+ ' Beautiful Soup.' % self._decode_markup(markup),
+ MarkupResemblesLocatorWarning
+ )
+ self._check_markup_is_url(markup)
+
+ rejections = []
+ success = False
+ for (self.markup, self.original_encoding, self.declared_html_encoding,
+ self.contains_replacement_characters) in (
+ self.builder.prepare_markup(
+ markup, from_encoding, exclude_encodings=exclude_encodings)):
+ self.reset()
+ try:
+ self._feed()
+ success = True
+ break
+ except ParserRejectedMarkup as e:
+ rejections.append(e)
+ pass
+
+ if not success:
+ other_exceptions = [str(e) for e in rejections]
+ raise ParserRejectedMarkup(
+ "The markup you provided was rejected by the parser. Trying a different parser or a different encoding may help.\n\nOriginal exception(s) from parser:\n " + "\n ".join(other_exceptions)
+ )
+
+ # Clear out the markup and remove the builder's circular
+ # reference to this object.
+ self.markup = None
+ self.builder.soup = None
+
+ def __copy__(self):
+ """Copy a BeautifulSoup object by converting the document to a string and parsing it again."""
+ copy = type(self)(
+ self.encode('utf-8'), builder=self.builder, from_encoding='utf-8'
+ )
+
+ # Although we encoded the tree to UTF-8, that may not have
+ # been the encoding of the original markup. Set the copy's
+ # .original_encoding to reflect the original object's
+ # .original_encoding.
+ copy.original_encoding = self.original_encoding
+ return copy
+
+ def __getstate__(self):
+ # Frequently a tree builder can't be pickled.
+ d = dict(self.__dict__)
+ if 'builder' in d and not self.builder.picklable:
+ d['builder'] = None
+ return d
+
+ @classmethod
+ def _decode_markup(cls, markup):
+ """Ensure `markup` is bytes so it's safe to send into warnings.warn.
+
+ TODO: warnings.warn had this problem back in 2010 but it might not
+ anymore.
+ """
+ if isinstance(markup, bytes):
+ decoded = markup.decode('utf-8', 'replace')
+ else:
+ decoded = markup
+ return decoded
+
+ @classmethod
+ def _check_markup_is_url(cls, markup):
+ """Error-handling method to raise a warning if incoming markup looks
+ like a URL.
+
+ :param markup: A string.
+ """
+ if isinstance(markup, bytes):
+ space = b' '
+ cant_start_with = (b"http:", b"https:")
+ elif isinstance(markup, str):
+ space = ' '
+ cant_start_with = ("http:", "https:")
+ else:
+ return
+
+ if any(markup.startswith(prefix) for prefix in cant_start_with):
+ if not space in markup:
+ warnings.warn(
+ '"%s" looks like a URL. Beautiful Soup is not an'
+ ' HTTP client. You should probably use an HTTP client like'
+ ' requests to get the document behind the URL, and feed'
+ ' that document to Beautiful Soup.' % cls._decode_markup(
+ markup
+ ),
+ MarkupResemblesLocatorWarning
+ )
+
+ def _feed(self):
+ """Internal method that parses previously set markup, creating a large
+ number of Tag and NavigableString objects.
+ """
+ # Convert the document to Unicode.
+ self.builder.reset()
+
+ self.builder.feed(self.markup)
+ # Close out any unfinished strings and close all the open tags.
+ self.endData()
+ while self.currentTag.name != self.ROOT_TAG_NAME:
+ self.popTag()
+
+ def reset(self):
+ """Reset this object to a state as though it had never parsed any
+ markup.
+ """
+ Tag.__init__(self, self, self.builder, self.ROOT_TAG_NAME)
+ self.hidden = 1
+ self.builder.reset()
+ self.current_data = []
+ self.currentTag = None
+ self.tagStack = []
+ self.preserve_whitespace_tag_stack = []
+ self.string_container_stack = []
+ self.pushTag(self)
+
+ def new_tag(self, name, namespace=None, nsprefix=None, attrs={},
+ sourceline=None, sourcepos=None, **kwattrs):
+ """Create a new Tag associated with this BeautifulSoup object.
+
+ :param name: The name of the new Tag.
+ :param namespace: The URI of the new Tag's XML namespace, if any.
+ :param prefix: The prefix for the new Tag's XML namespace, if any.
+ :param attrs: A dictionary of this Tag's attribute values; can
+ be used instead of `kwattrs` for attributes like 'class'
+ that are reserved words in Python.
+ :param sourceline: The line number where this tag was
+ (purportedly) found in its source document.
+ :param sourcepos: The character position within `sourceline` where this
+ tag was (purportedly) found.
+ :param kwattrs: Keyword arguments for the new Tag's attribute values.
+
+ """
+ kwattrs.update(attrs)
+ return self.element_classes.get(Tag, Tag)(
+ None, self.builder, name, namespace, nsprefix, kwattrs,
+ sourceline=sourceline, sourcepos=sourcepos
+ )
+
+ def string_container(self, base_class=None):
+ container = base_class or NavigableString
+
+ # There may be a general override of NavigableString.
+ container = self.element_classes.get(
+ container, container
+ )
+
+ # On top of that, we may be inside a tag that needs a special
+ # container class.
+ if self.string_container_stack:
+ container = self.builder.string_containers.get(
+ self.string_container_stack[-1].name, container
+ )
+ return container
+
+ def new_string(self, s, subclass=None):
+ """Create a new NavigableString associated with this BeautifulSoup
+ object.
+ """
+ container = self.string_container(subclass)
+ return container(s)
+
+ def insert_before(self, successor):
+ """This method is part of the PageElement API, but `BeautifulSoup` doesn't implement
+ it because there is nothing before or after it in the parse tree.
+ """
+ raise NotImplementedError("BeautifulSoup objects don't support insert_before().")
+
+ def insert_after(self, successor):
+ """This method is part of the PageElement API, but `BeautifulSoup` doesn't implement
+ it because there is nothing before or after it in the parse tree.
+ """
+ raise NotImplementedError("BeautifulSoup objects don't support insert_after().")
+
+ def popTag(self):
+ """Internal method called by _popToTag when a tag is closed."""
+ tag = self.tagStack.pop()
+ if self.preserve_whitespace_tag_stack and tag == self.preserve_whitespace_tag_stack[-1]:
+ self.preserve_whitespace_tag_stack.pop()
+ if self.string_container_stack and tag == self.string_container_stack[-1]:
+ self.string_container_stack.pop()
+ #print("Pop", tag.name)
+ if self.tagStack:
+ self.currentTag = self.tagStack[-1]
+ return self.currentTag
+
+ def pushTag(self, tag):
+ """Internal method called by handle_starttag when a tag is opened."""
+ #print("Push", tag.name)
+ if self.currentTag is not None:
+ self.currentTag.contents.append(tag)
+ self.tagStack.append(tag)
+ self.currentTag = self.tagStack[-1]
+ if tag.name in self.builder.preserve_whitespace_tags:
+ self.preserve_whitespace_tag_stack.append(tag)
+ if tag.name in self.builder.string_containers:
+ self.string_container_stack.append(tag)
+
+ def endData(self, containerClass=None):
+ """Method called by the TreeBuilder when the end of a data segment
+ occurs.
+ """
+ containerClass = self.string_container(containerClass)
+
+ if self.current_data:
+ current_data = ''.join(self.current_data)
+ # If whitespace is not preserved, and this string contains
+ # nothing but ASCII spaces, replace it with a single space
+ # or newline.
+ if not self.preserve_whitespace_tag_stack:
+ strippable = True
+ for i in current_data:
+ if i not in self.ASCII_SPACES:
+ strippable = False
+ break
+ if strippable:
+ if '\n' in current_data:
+ current_data = '\n'
+ else:
+ current_data = ' '
+
+ # Reset the data collector.
+ self.current_data = []
+
+ # Should we add this string to the tree at all?
+ if self.parse_only and len(self.tagStack) <= 1 and \
+ (not self.parse_only.text or \
+ not self.parse_only.search(current_data)):
+ return
+
+ o = containerClass(current_data)
+ self.object_was_parsed(o)
+
+ def object_was_parsed(self, o, parent=None, most_recent_element=None):
+ """Method called by the TreeBuilder to integrate an object into the parse tree."""
+ if parent is None:
+ parent = self.currentTag
+ if most_recent_element is not None:
+ previous_element = most_recent_element
+ else:
+ previous_element = self._most_recent_element
+
+ next_element = previous_sibling = next_sibling = None
+ if isinstance(o, Tag):
+ next_element = o.next_element
+ next_sibling = o.next_sibling
+ previous_sibling = o.previous_sibling
+ if previous_element is None:
+ previous_element = o.previous_element
+
+ fix = parent.next_element is not None
+
+ o.setup(parent, previous_element, next_element, previous_sibling, next_sibling)
+
+ self._most_recent_element = o
+ parent.contents.append(o)
+
+ # Check if we are inserting into an already parsed node.
+ if fix:
+ self._linkage_fixer(parent)
+
+ def _linkage_fixer(self, el):
+ """Make sure linkage of this fragment is sound."""
+
+ first = el.contents[0]
+ child = el.contents[-1]
+ descendant = child
+
+ if child is first and el.parent is not None:
+ # Parent should be linked to first child
+ el.next_element = child
+ # We are no longer linked to whatever this element is
+ prev_el = child.previous_element
+ if prev_el is not None and prev_el is not el:
+ prev_el.next_element = None
+ # First child should be linked to the parent, and no previous siblings.
+ child.previous_element = el
+ child.previous_sibling = None
+
+ # We have no sibling as we've been appended as the last.
+ child.next_sibling = None
+
+ # This index is a tag, dig deeper for a "last descendant"
+ if isinstance(child, Tag) and child.contents:
+ descendant = child._last_descendant(False)
+
+ # As the final step, link last descendant. It should be linked
+ # to the parent's next sibling (if found), else walk up the chain
+ # and find a parent with a sibling. It should have no next sibling.
+ descendant.next_element = None
+ descendant.next_sibling = None
+ target = el
+ while True:
+ if target is None:
+ break
+ elif target.next_sibling is not None:
+ descendant.next_element = target.next_sibling
+ target.next_sibling.previous_element = child
+ break
+ target = target.parent
+
+ def _popToTag(self, name, nsprefix=None, inclusivePop=True):
+ """Pops the tag stack up to and including the most recent
+ instance of the given tag.
+
+ :param name: Pop up to the most recent tag with this name.
+ :param nsprefix: The namespace prefix that goes with `name`.
+ :param inclusivePop: It this is false, pops the tag stack up
+ to but *not* including the most recent instqance of the
+ given tag.
+ """
+ #print("Popping to %s" % name)
+ if name == self.ROOT_TAG_NAME:
+ # The BeautifulSoup object itself can never be popped.
+ return
+
+ most_recently_popped = None
+
+ stack_size = len(self.tagStack)
+ for i in range(stack_size - 1, 0, -1):
+ t = self.tagStack[i]
+ if (name == t.name and nsprefix == t.prefix):
+ if inclusivePop:
+ most_recently_popped = self.popTag()
+ break
+ most_recently_popped = self.popTag()
+
+ return most_recently_popped
+
+ def handle_starttag(self, name, namespace, nsprefix, attrs, sourceline=None,
+ sourcepos=None):
+ """Called by the tree builder when a new tag is encountered.
+
+ :param name: Name of the tag.
+ :param nsprefix: Namespace prefix for the tag.
+ :param attrs: A dictionary of attribute values.
+ :param sourceline: The line number where this tag was found in its
+ source document.
+ :param sourcepos: The character position within `sourceline` where this
+ tag was found.
+
+ If this method returns None, the tag was rejected by an active
+ SoupStrainer. You should proceed as if the tag had not occurred
+ in the document. For instance, if this was a self-closing tag,
+ don't call handle_endtag.
+ """
+ # print("Start tag %s: %s" % (name, attrs))
+ self.endData()
+
+ if (self.parse_only and len(self.tagStack) <= 1
+ and (self.parse_only.text
+ or not self.parse_only.search_tag(name, attrs))):
+ return None
+
+ tag = self.element_classes.get(Tag, Tag)(
+ self, self.builder, name, namespace, nsprefix, attrs,
+ self.currentTag, self._most_recent_element,
+ sourceline=sourceline, sourcepos=sourcepos
+ )
+ if tag is None:
+ return tag
+ if self._most_recent_element is not None:
+ self._most_recent_element.next_element = tag
+ self._most_recent_element = tag
+ self.pushTag(tag)
+ return tag
+
+ def handle_endtag(self, name, nsprefix=None):
+ """Called by the tree builder when an ending tag is encountered.
+
+ :param name: Name of the tag.
+ :param nsprefix: Namespace prefix for the tag.
+ """
+ #print("End tag: " + name)
+ self.endData()
+ self._popToTag(name, nsprefix)
+
+ def handle_data(self, data):
+ """Called by the tree builder when a chunk of textual data is encountered."""
+ self.current_data.append(data)
+
+ def decode(self, pretty_print=False,
+ eventual_encoding=DEFAULT_OUTPUT_ENCODING,
+ formatter="minimal"):
+ """Returns a string or Unicode representation of the parse tree
+ as an HTML or XML document.
+
+ :param pretty_print: If this is True, indentation will be used to
+ make the document more readable.
+ :param eventual_encoding: The encoding of the final document.
+ If this is None, the document will be a Unicode string.
+ """
+ if self.is_xml:
+ # Print the XML declaration
+ encoding_part = ''
+ if eventual_encoding in PYTHON_SPECIFIC_ENCODINGS:
+ # This is a special Python encoding; it can't actually
+ # go into an XML document because it means nothing
+ # outside of Python.
+ eventual_encoding = None
+ if eventual_encoding != None:
+ encoding_part = ' encoding="%s"' % eventual_encoding
+ prefix = '\n' % encoding_part
+ else:
+ prefix = ''
+ if not pretty_print:
+ indent_level = None
+ else:
+ indent_level = 0
+ return prefix + super(BeautifulSoup, self).decode(
+ indent_level, eventual_encoding, formatter)
+
+# Aliases to make it easier to get started quickly, e.g. 'from bs4 import _soup'
+_s = BeautifulSoup
+_soup = BeautifulSoup
+
+class BeautifulStoneSoup(BeautifulSoup):
+ """Deprecated interface to an XML parser."""
+
+ def __init__(self, *args, **kwargs):
+ kwargs['features'] = 'xml'
+ warnings.warn(
+ 'The BeautifulStoneSoup class is deprecated. Instead of using '
+ 'it, pass features="xml" into the BeautifulSoup constructor.')
+ super(BeautifulStoneSoup, self).__init__(*args, **kwargs)
+
+
+class StopParsing(Exception):
+ """Exception raised by a TreeBuilder if it's unable to continue parsing."""
+ pass
+
+class FeatureNotFound(ValueError):
+ """Exception raised by the BeautifulSoup constructor if no parser with the
+ requested features is found.
+ """
+ pass
+
+
+#If this file is run as a script, act as an HTML pretty-printer.
+if __name__ == '__main__':
+ import sys
+ soup = BeautifulSoup(sys.stdin)
+ print((soup.prettify()))
diff --git a/venv/Lib/site-packages/bs4/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/bs4/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fc75f9a23e59897c3fb062c808923715520a7736
GIT binary patch
literal 22732
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 )XHS31O%S#YuW&bXdl
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