mirror of
https://github.com/bellingcat/vk-url-scraper.git
synced 2026-06-08 19:38:37 +03:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e30b81d16 | ||
|
|
72bc355606 | ||
|
|
7f59eefb73 | ||
|
|
30003c524e | ||
|
|
d1b27bef1d | ||
|
|
e5e9e08ee6 | ||
|
|
3a8a3f54c0 | ||
|
|
4d73864dbb | ||
|
|
ceaa8e45f3 | ||
|
|
007c8e07a8 | ||
|
|
a515b2c3de | ||
|
|
54540cd132 | ||
|
|
cfb13e5d82 | ||
|
|
926c3cb8a4 | ||
|
|
15ebe2e66c | ||
|
|
eaff88b2d9 | ||
|
|
a6d066a192 | ||
|
|
9078a17400 | ||
|
|
17b516bd7f | ||
|
|
8bd182b041 | ||
|
|
0b8abfb5cb | ||
|
|
cf5fb91c84 | ||
|
|
5c965102a4 | ||
|
|
df10e6f55f | ||
|
|
863dd44463 | ||
|
|
578ec81443 | ||
|
|
c32caec442 | ||
|
|
80b43f7c95 | ||
|
|
90b72b6d22 | ||
|
|
d96e0c0a3a | ||
|
|
db03a4c0f6 | ||
|
|
cf100ee69e | ||
|
|
a09cf32b3e | ||
|
|
e1eb3ed620 | ||
|
|
72bd951d9c | ||
|
|
59d53be68b | ||
|
|
24a1313a65 | ||
|
|
64df4eec28 | ||
|
|
42bdc1441c | ||
|
|
c25880ee6d | ||
|
|
e1e3648852 | ||
|
|
c74dc280d8 | ||
|
|
ab15b35008 | ||
|
|
62c4536d0b | ||
|
|
eac0fc4904 | ||
|
|
1341cd866f | ||
|
|
7824c2922d | ||
|
|
c9a3ece9af | ||
|
|
50b78d618a | ||
|
|
c4a1333428 | ||
|
|
edb02ae049 | ||
|
|
284fd3fdf7 | ||
|
|
3078495a2a | ||
|
|
187cfa83c8 |
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
VK_USERNAME="your username"
|
||||
VK_PASSWORD="your password"
|
||||
VK_TOKEN="optional token"
|
||||
5
.github/actions/setup-venv/action.yml
vendored
5
.github/actions/setup-venv/action.yml
vendored
@@ -16,6 +16,11 @@ runs:
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
|
||||
- shell: bash
|
||||
run: |
|
||||
# install ffmpeg
|
||||
sudo apt install ffmpeg
|
||||
|
||||
- shell: bash
|
||||
run: |
|
||||
# Install prerequisites.
|
||||
|
||||
36
.github/pull_request_template.md
vendored
36
.github/pull_request_template.md
vendored
@@ -1,18 +1,18 @@
|
||||
<!-- To ensure we can review your pull request promptly please complete this template entirely. -->
|
||||
|
||||
<!-- Please reference the issue number here. You can replace "Fixes" with "Closes" if it makes more sense. -->
|
||||
Fixes #
|
||||
|
||||
Changes proposed in this pull request:
|
||||
<!-- Please list all changes/additions here. -->
|
||||
-
|
||||
|
||||
## Before submitting
|
||||
|
||||
<!-- Please complete this checklist BEFORE submitting your PR to speed along the review process. -->
|
||||
- [ ] I've read and followed all steps in the [Making a pull request](https://github.com/bellingcat/vk-url-scraper/blob/main/CONTRIBUTING.md#making-a-pull-request)
|
||||
section of the `CONTRIBUTING` docs.
|
||||
- [ ] I've updated or added any relevant docstrings following the syntax described in the
|
||||
[Writing docstrings](https://github.com/bellingcat/vk-url-scraper/blob/main/CONTRIBUTING.md#writing-docstrings) section of the `CONTRIBUTING` docs.
|
||||
- [ ] If this PR fixes a bug, I've added a test that will fail without my fix.
|
||||
- [ ] If this PR adds a new feature, I've added tests that sufficiently cover my new functionality.
|
||||
<!-- To ensure we can review your pull request promptly please complete this template entirely. -->
|
||||
|
||||
<!-- Please reference the issue number here. You can replace "Fixes" with "Closes" if it makes more sense. -->
|
||||
Fixes #
|
||||
|
||||
Changes proposed in this pull request:
|
||||
<!-- Please list all changes/additions here. -->
|
||||
-
|
||||
|
||||
## Before submitting
|
||||
|
||||
<!-- Please complete this checklist BEFORE submitting your PR to speed along the review process. -->
|
||||
- [ ] I've read and followed all steps in the [Making a pull request](https://github.com/bellingcat/vk-url-scraper/blob/main/CONTRIBUTING.md#making-a-pull-request)
|
||||
section of the `CONTRIBUTING` docs.
|
||||
- [ ] I've updated or added any relevant docstrings following the syntax described in the
|
||||
[Writing docstrings](https://github.com/bellingcat/vk-url-scraper/blob/main/CONTRIBUTING.md#writing-docstrings) section of the `CONTRIBUTING` docs.
|
||||
- [ ] If this PR fixes a bug, I've added a test that will fail without my fix.
|
||||
- [ ] If this PR adds a new feature, I've added tests that sufficiently cover my new functionality.
|
||||
|
||||
9
.github/workflows/main.yml
vendored
9
.github/workflows/main.yml
vendored
@@ -20,6 +20,7 @@ env:
|
||||
PYTHONPATH: ./
|
||||
VK_USERNAME: ${{ secrets.VK_USERNAME }}
|
||||
VK_PASSWORD: ${{ secrets.VK_PASSWORD }}
|
||||
VK_TOKEN: ${{ secrets.VK_TOKEN }}
|
||||
|
||||
jobs:
|
||||
checks:
|
||||
@@ -30,10 +31,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python: ['3.7', '3.10']
|
||||
task:
|
||||
task: # --show-capture=no on purpose
|
||||
- name: Test
|
||||
run: |
|
||||
pytest --color=yes tests/
|
||||
pytest --show-capture=no --color=yes tests/
|
||||
|
||||
include:
|
||||
- python: '3.10'
|
||||
@@ -121,10 +122,6 @@ jobs:
|
||||
name: package
|
||||
path: dist
|
||||
|
||||
# - name: Generate release notes
|
||||
# run: |
|
||||
# python scripts/release_notes.py > ${{ github.workspace }}-RELEASE_NOTES.md
|
||||
|
||||
- name: Publish package to PyPI
|
||||
run: |
|
||||
twine upload -u '${{ secrets.PYPI_USERNAME }}' -p '${{ secrets.PYPI_PASSWORD }}' dist/*
|
||||
|
||||
27
.github/workflows/pr_checks.yml
vendored
27
.github/workflows/pr_checks.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: PR Checks
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'vk_url_scraper/**'
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
name: CHANGELOG
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Check that CHANGELOG has been updated
|
||||
run: |
|
||||
# If this step fails, this means you haven't updated the CHANGELOG.md
|
||||
# file with notes on your contribution.
|
||||
git diff --name-only $(git merge-base origin/main HEAD) | grep '^CHANGELOG.md$' && echo "Thanks for helping keep our CHANGELOG up-to-date!"
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
.env
|
||||
vk_config.v2.json
|
||||
output/
|
||||
tmp*/
|
||||
# build artifacts
|
||||
|
||||
.eggs/
|
||||
|
||||
@@ -2,7 +2,7 @@ version: 2
|
||||
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
fail_on_warning: true
|
||||
fail_on_warning: false
|
||||
|
||||
python:
|
||||
version: "3.8"
|
||||
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,13 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [0.1.2]
|
||||
### Added wall scraper with tests
|
||||
### Added photo scraper with tests
|
||||
### Added scraper with tests
|
||||
@@ -156,8 +156,6 @@ When you're ready to contribute code to address an open issue, please follow the
|
||||
|
||||
If the build fails, it's most likely due to small formatting issues. If the error message isn't clear, feel free to comment on this in your pull request.
|
||||
|
||||
And finally, please update the [CHANGELOG](https://github.com/bellingcat/vk-url-scraper/blob/main/CHANGELOG.md) with notes on your contribution in the "Unreleased" section at the top.
|
||||
|
||||
After all of the above checks have passed, you can now open [a new GitHub pull request](https://github.com/bellingcat/vk-url-scraper/pulls).
|
||||
Make sure you have a clear description of the problem and the solution, and include a link to relevant issues.
|
||||
|
||||
|
||||
8
Makefile
8
Makefile
@@ -5,8 +5,12 @@ docs :
|
||||
|
||||
.PHONY : run-checks
|
||||
run-checks :
|
||||
isort --check .
|
||||
black --check .
|
||||
# do with --check to not change files
|
||||
# isort --check .
|
||||
# black --check .
|
||||
# do like this to fix files
|
||||
isort .
|
||||
black .
|
||||
flake8 .
|
||||
mypy .
|
||||
CUDA_VISIBLE_DEVICES='' pytest -v --color=yes --doctest-modules tests/ vk_url_scraper/
|
||||
|
||||
6
Pipfile
6
Pipfile
@@ -5,6 +5,7 @@ name = "pypi"
|
||||
|
||||
[packages]
|
||||
vk-api = "*"
|
||||
yt-dlp = "*"
|
||||
|
||||
[dev-packages]
|
||||
sphinx-copybutton = "==0.5.0"
|
||||
@@ -17,7 +18,7 @@ pytest-sphinx = "*"
|
||||
pytest-cov = "*"
|
||||
twine = ">=1.11.0"
|
||||
sphinx = ">=4.3.0,<5.1.0"
|
||||
furo = "==2022.6.4.1"
|
||||
furo = "==2022.6.21"
|
||||
myst-parser = ">=0.15.2,<0.19.0"
|
||||
sphinx-autobuild = "==2021.3.14"
|
||||
sphinx-autodoc-typehints = "*"
|
||||
@@ -25,3 +26,6 @@ python-dotenv = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
||||
[pipenv]
|
||||
allow_prereleases = true
|
||||
|
||||
584
Pipfile.lock
generated
584
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "bab533e734f6da55647cc76a9f5a51d46c641723d485e38a16e2e31bca097130"
|
||||
"sha256": "db41a24084eab3b2ff8328dae834e79803e37237892ffd04eb3060e880a82c92"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -16,6 +16,74 @@
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"brotli": {
|
||||
"hashes": [
|
||||
"sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d",
|
||||
"sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8",
|
||||
"sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b",
|
||||
"sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c",
|
||||
"sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c",
|
||||
"sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70",
|
||||
"sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f",
|
||||
"sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181",
|
||||
"sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130",
|
||||
"sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19",
|
||||
"sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa",
|
||||
"sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429",
|
||||
"sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126",
|
||||
"sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4",
|
||||
"sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0",
|
||||
"sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b",
|
||||
"sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6",
|
||||
"sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438",
|
||||
"sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f",
|
||||
"sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389",
|
||||
"sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6",
|
||||
"sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26",
|
||||
"sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7",
|
||||
"sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14",
|
||||
"sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2",
|
||||
"sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430",
|
||||
"sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296",
|
||||
"sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12",
|
||||
"sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f",
|
||||
"sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d",
|
||||
"sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a",
|
||||
"sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452",
|
||||
"sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c",
|
||||
"sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761",
|
||||
"sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649",
|
||||
"sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b",
|
||||
"sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea",
|
||||
"sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c",
|
||||
"sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a",
|
||||
"sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031",
|
||||
"sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267",
|
||||
"sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5",
|
||||
"sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7",
|
||||
"sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d",
|
||||
"sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c",
|
||||
"sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43",
|
||||
"sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa",
|
||||
"sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17",
|
||||
"sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb",
|
||||
"sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb",
|
||||
"sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b",
|
||||
"sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4",
|
||||
"sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3",
|
||||
"sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7",
|
||||
"sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1",
|
||||
"sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb",
|
||||
"sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91",
|
||||
"sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b",
|
||||
"sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1",
|
||||
"sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806",
|
||||
"sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3",
|
||||
"sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"
|
||||
],
|
||||
"markers": "platform_python_implementation == 'CPython'",
|
||||
"version": "==1.0.9"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d",
|
||||
@@ -26,35 +94,79 @@
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
|
||||
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
|
||||
"sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5",
|
||||
"sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"version": "==2.0.12"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
|
||||
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.3"
|
||||
},
|
||||
"mutagen": {
|
||||
"hashes": [
|
||||
"sha256:6397602efb3c2d7baebd2166ed85731ae1c1d475abca22090b7141ff5034b3e1",
|
||||
"sha256:9c9f243fcec7f410f138cb12c21c84c64fde4195481a30c9bfb05b5f003adfed"
|
||||
],
|
||||
"markers": "python_version >= '3.5' and python_version < '4'",
|
||||
"version": "==1.45.1"
|
||||
},
|
||||
"pycryptodomex": {
|
||||
"hashes": [
|
||||
"sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380",
|
||||
"sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa",
|
||||
"sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c",
|
||||
"sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b",
|
||||
"sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1",
|
||||
"sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a",
|
||||
"sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4",
|
||||
"sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6",
|
||||
"sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2",
|
||||
"sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780",
|
||||
"sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64",
|
||||
"sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f",
|
||||
"sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a",
|
||||
"sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a",
|
||||
"sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf",
|
||||
"sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed",
|
||||
"sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5",
|
||||
"sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb",
|
||||
"sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794",
|
||||
"sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb",
|
||||
"sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd",
|
||||
"sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381",
|
||||
"sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870",
|
||||
"sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86",
|
||||
"sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0",
|
||||
"sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d",
|
||||
"sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d",
|
||||
"sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab",
|
||||
"sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4",
|
||||
"sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==3.15.0"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f",
|
||||
"sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"
|
||||
"sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983",
|
||||
"sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"
|
||||
],
|
||||
"markers": "python_version >= '3.7' and python_version < '4'",
|
||||
"version": "==2.28.0"
|
||||
"version": "==2.28.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
||||
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
||||
"sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec",
|
||||
"sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.9"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'",
|
||||
"version": "==1.26.10"
|
||||
},
|
||||
"vk-api": {
|
||||
"hashes": [
|
||||
@@ -63,6 +175,68 @@
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==11.9.8"
|
||||
},
|
||||
"websockets": {
|
||||
"hashes": [
|
||||
"sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af",
|
||||
"sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c",
|
||||
"sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76",
|
||||
"sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47",
|
||||
"sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69",
|
||||
"sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079",
|
||||
"sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c",
|
||||
"sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55",
|
||||
"sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02",
|
||||
"sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559",
|
||||
"sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3",
|
||||
"sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e",
|
||||
"sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978",
|
||||
"sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98",
|
||||
"sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae",
|
||||
"sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755",
|
||||
"sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d",
|
||||
"sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991",
|
||||
"sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1",
|
||||
"sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680",
|
||||
"sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247",
|
||||
"sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f",
|
||||
"sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2",
|
||||
"sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7",
|
||||
"sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4",
|
||||
"sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667",
|
||||
"sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb",
|
||||
"sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094",
|
||||
"sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36",
|
||||
"sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79",
|
||||
"sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500",
|
||||
"sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e",
|
||||
"sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582",
|
||||
"sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442",
|
||||
"sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd",
|
||||
"sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6",
|
||||
"sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731",
|
||||
"sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4",
|
||||
"sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d",
|
||||
"sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8",
|
||||
"sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f",
|
||||
"sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677",
|
||||
"sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8",
|
||||
"sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9",
|
||||
"sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e",
|
||||
"sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b",
|
||||
"sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916",
|
||||
"sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==10.3"
|
||||
},
|
||||
"yt-dlp": {
|
||||
"hashes": [
|
||||
"sha256:0e7b81fc6ac8d1b7d3fffa79f9044ca4163784422582c9a3593305da2a69ec02",
|
||||
"sha256:d7d1f81d230756f094b4d9ee59b37b2c13b2e63ff5fb72cda53625edb072cdae"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2022.7.18"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
@@ -128,11 +302,11 @@
|
||||
},
|
||||
"bleach": {
|
||||
"hashes": [
|
||||
"sha256:08a1fe86d253b5c88c92cc3d810fd8048a16d15762e1e5b74d502256e5926aa1",
|
||||
"sha256:c6d6cc054bdc9c83b48b8083e236e5f00f238428666d2ce2e083eaa5fd568565"
|
||||
"sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a",
|
||||
"sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==5.0.0"
|
||||
"version": "==5.0.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
@@ -144,66 +318,80 @@
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3",
|
||||
"sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2",
|
||||
"sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636",
|
||||
"sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20",
|
||||
"sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728",
|
||||
"sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27",
|
||||
"sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66",
|
||||
"sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443",
|
||||
"sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0",
|
||||
"sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7",
|
||||
"sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39",
|
||||
"sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605",
|
||||
"sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a",
|
||||
"sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37",
|
||||
"sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029",
|
||||
"sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139",
|
||||
"sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc",
|
||||
"sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df",
|
||||
"sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14",
|
||||
"sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880",
|
||||
"sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2",
|
||||
"sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a",
|
||||
"sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e",
|
||||
"sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474",
|
||||
"sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024",
|
||||
"sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8",
|
||||
"sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0",
|
||||
"sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e",
|
||||
"sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a",
|
||||
"sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e",
|
||||
"sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032",
|
||||
"sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6",
|
||||
"sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e",
|
||||
"sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b",
|
||||
"sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e",
|
||||
"sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954",
|
||||
"sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962",
|
||||
"sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c",
|
||||
"sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4",
|
||||
"sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55",
|
||||
"sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962",
|
||||
"sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023",
|
||||
"sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c",
|
||||
"sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6",
|
||||
"sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8",
|
||||
"sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382",
|
||||
"sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7",
|
||||
"sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc",
|
||||
"sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997",
|
||||
"sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"
|
||||
"sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5",
|
||||
"sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef",
|
||||
"sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104",
|
||||
"sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426",
|
||||
"sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405",
|
||||
"sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375",
|
||||
"sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a",
|
||||
"sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e",
|
||||
"sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc",
|
||||
"sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf",
|
||||
"sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185",
|
||||
"sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497",
|
||||
"sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3",
|
||||
"sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35",
|
||||
"sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c",
|
||||
"sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83",
|
||||
"sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21",
|
||||
"sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca",
|
||||
"sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984",
|
||||
"sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac",
|
||||
"sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd",
|
||||
"sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee",
|
||||
"sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a",
|
||||
"sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2",
|
||||
"sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192",
|
||||
"sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7",
|
||||
"sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585",
|
||||
"sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f",
|
||||
"sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e",
|
||||
"sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27",
|
||||
"sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b",
|
||||
"sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e",
|
||||
"sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e",
|
||||
"sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d",
|
||||
"sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c",
|
||||
"sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415",
|
||||
"sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82",
|
||||
"sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02",
|
||||
"sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314",
|
||||
"sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325",
|
||||
"sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c",
|
||||
"sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3",
|
||||
"sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914",
|
||||
"sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045",
|
||||
"sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d",
|
||||
"sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9",
|
||||
"sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5",
|
||||
"sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2",
|
||||
"sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c",
|
||||
"sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3",
|
||||
"sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2",
|
||||
"sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8",
|
||||
"sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d",
|
||||
"sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d",
|
||||
"sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9",
|
||||
"sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162",
|
||||
"sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76",
|
||||
"sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4",
|
||||
"sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e",
|
||||
"sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9",
|
||||
"sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6",
|
||||
"sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b",
|
||||
"sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01",
|
||||
"sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"
|
||||
],
|
||||
"version": "==1.15.0"
|
||||
"version": "==1.15.1"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
|
||||
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
|
||||
"sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5",
|
||||
"sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"version": "==2.0.12"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
@@ -233,78 +421,78 @@
|
||||
"toml"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749",
|
||||
"sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982",
|
||||
"sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3",
|
||||
"sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9",
|
||||
"sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428",
|
||||
"sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e",
|
||||
"sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c",
|
||||
"sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9",
|
||||
"sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264",
|
||||
"sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605",
|
||||
"sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397",
|
||||
"sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d",
|
||||
"sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c",
|
||||
"sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815",
|
||||
"sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068",
|
||||
"sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b",
|
||||
"sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4",
|
||||
"sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4",
|
||||
"sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3",
|
||||
"sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84",
|
||||
"sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83",
|
||||
"sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4",
|
||||
"sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8",
|
||||
"sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb",
|
||||
"sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d",
|
||||
"sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df",
|
||||
"sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6",
|
||||
"sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b",
|
||||
"sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72",
|
||||
"sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13",
|
||||
"sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df",
|
||||
"sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc",
|
||||
"sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6",
|
||||
"sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28",
|
||||
"sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b",
|
||||
"sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4",
|
||||
"sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad",
|
||||
"sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46",
|
||||
"sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3",
|
||||
"sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9",
|
||||
"sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"
|
||||
"sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32",
|
||||
"sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7",
|
||||
"sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996",
|
||||
"sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55",
|
||||
"sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46",
|
||||
"sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de",
|
||||
"sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039",
|
||||
"sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee",
|
||||
"sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1",
|
||||
"sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f",
|
||||
"sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63",
|
||||
"sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083",
|
||||
"sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe",
|
||||
"sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0",
|
||||
"sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6",
|
||||
"sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe",
|
||||
"sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933",
|
||||
"sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0",
|
||||
"sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c",
|
||||
"sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07",
|
||||
"sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8",
|
||||
"sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b",
|
||||
"sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e",
|
||||
"sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120",
|
||||
"sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f",
|
||||
"sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e",
|
||||
"sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd",
|
||||
"sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f",
|
||||
"sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386",
|
||||
"sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8",
|
||||
"sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae",
|
||||
"sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc",
|
||||
"sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783",
|
||||
"sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d",
|
||||
"sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c",
|
||||
"sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97",
|
||||
"sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978",
|
||||
"sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf",
|
||||
"sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29",
|
||||
"sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39",
|
||||
"sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==6.4.1"
|
||||
"version": "==6.4.2"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804",
|
||||
"sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178",
|
||||
"sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717",
|
||||
"sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982",
|
||||
"sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004",
|
||||
"sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe",
|
||||
"sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452",
|
||||
"sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336",
|
||||
"sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4",
|
||||
"sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15",
|
||||
"sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d",
|
||||
"sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c",
|
||||
"sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0",
|
||||
"sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06",
|
||||
"sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9",
|
||||
"sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1",
|
||||
"sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023",
|
||||
"sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de",
|
||||
"sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f",
|
||||
"sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181",
|
||||
"sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e",
|
||||
"sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a"
|
||||
"sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59",
|
||||
"sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596",
|
||||
"sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3",
|
||||
"sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5",
|
||||
"sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab",
|
||||
"sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884",
|
||||
"sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82",
|
||||
"sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b",
|
||||
"sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441",
|
||||
"sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa",
|
||||
"sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d",
|
||||
"sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b",
|
||||
"sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a",
|
||||
"sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6",
|
||||
"sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157",
|
||||
"sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280",
|
||||
"sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282",
|
||||
"sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67",
|
||||
"sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8",
|
||||
"sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046",
|
||||
"sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327",
|
||||
"sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==37.0.2"
|
||||
"version": "==37.0.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
@@ -324,35 +512,35 @@
|
||||
},
|
||||
"furo": {
|
||||
"hashes": [
|
||||
"sha256:79f2d3a61e3d971c0acd59f53d3202e7336789cd893f7bdc3cc7bc37d6ef252c",
|
||||
"sha256:c927848edf3292030d0719ebdab9e16d56f1b91c68562b9be316aa5b843775ab"
|
||||
"sha256:061b68e323345e27fcba024cf33a1e77f3dfd8d9987410be822749a706e2add6",
|
||||
"sha256:9aa983b7488a4601d13113884bfb7254502c8729942e073a0acb87a5512af223"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2022.6.4.1"
|
||||
"version": "==2022.6.21"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
|
||||
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.3"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c",
|
||||
"sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"
|
||||
"sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b",
|
||||
"sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.3.0"
|
||||
"version": "==1.4.1"
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700",
|
||||
"sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"
|
||||
"sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670",
|
||||
"sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.11.4"
|
||||
"version": "==4.12.0"
|
||||
},
|
||||
"iniconfig": {
|
||||
"hashes": [
|
||||
@@ -387,11 +575,11 @@
|
||||
},
|
||||
"keyring": {
|
||||
"hashes": [
|
||||
"sha256:372ff2fc43ab779e3f87911c26e6c7acc8bb440cbd82683e383ca37594cb0617",
|
||||
"sha256:3ac00c26e4c93739e19103091a9986a9f79665a78cf15a4df1dba7ea9ac8da2f"
|
||||
"sha256:782e1cd1132e91bf459fcd243bcf25b326015c1ac0b198e4408f91fa6791062b",
|
||||
"sha256:e67fc91a7955785fd2efcbccdd72d7dacf136dbc381d27de305b2b660b3de886"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.6.0"
|
||||
"version": "==23.7.0"
|
||||
},
|
||||
"livereload": {
|
||||
"hashes": [
|
||||
@@ -694,11 +882,11 @@
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f",
|
||||
"sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"
|
||||
"sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983",
|
||||
"sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"
|
||||
],
|
||||
"markers": "python_version >= '3.7' and python_version < '4'",
|
||||
"version": "==2.28.0"
|
||||
"version": "==2.28.1"
|
||||
},
|
||||
"requests-toolbelt": {
|
||||
"hashes": [
|
||||
@@ -717,11 +905,11 @@
|
||||
},
|
||||
"rich": {
|
||||
"hashes": [
|
||||
"sha256:4c586de507202505346f3e32d1363eb9ed6932f0c2f63184dea88983ff4971e2",
|
||||
"sha256:d2bbd99c320a2532ac71ff6a3164867884357da3e3301f0240090c5d2fdac7ec"
|
||||
"sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb",
|
||||
"sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca"
|
||||
],
|
||||
"markers": "python_version < '4' and python_full_version >= '3.6.3'",
|
||||
"version": "==12.4.4"
|
||||
"markers": "python_full_version >= '3.6.3' and python_full_version < '4.0.0'",
|
||||
"version": "==12.5.1"
|
||||
},
|
||||
"secretstorage": {
|
||||
"hashes": [
|
||||
@@ -780,11 +968,11 @@
|
||||
},
|
||||
"sphinx-basic-ng": {
|
||||
"hashes": [
|
||||
"sha256:9aecb5345816998789ef76658a83e3c0a12aafa14b17d40e28cd4aaeb94d1517",
|
||||
"sha256:bf9a8fda0379c7d2ab51c9543f2b18e014b77fb295b49d64f3c1a910c863b34f"
|
||||
"sha256:cffffb14914ddd26c94b1330df1d72dab5a42e220aaeb5953076a40b9c50e801",
|
||||
"sha256:e8b6efd2c5ece014156de76065eda01ddfca0fee465aa020b1e3c12f84570bbe"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.0.1a11"
|
||||
"version": "==0.0.1a12"
|
||||
},
|
||||
"sphinx-copybutton": {
|
||||
"hashes": [
|
||||
@@ -852,50 +1040,20 @@
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb",
|
||||
"sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c",
|
||||
"sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288",
|
||||
"sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95",
|
||||
"sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558",
|
||||
"sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe",
|
||||
"sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791",
|
||||
"sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d",
|
||||
"sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326",
|
||||
"sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b",
|
||||
"sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4",
|
||||
"sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c",
|
||||
"sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910",
|
||||
"sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5",
|
||||
"sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c",
|
||||
"sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0",
|
||||
"sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675",
|
||||
"sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd",
|
||||
"sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f",
|
||||
"sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c",
|
||||
"sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea",
|
||||
"sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6",
|
||||
"sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05",
|
||||
"sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd",
|
||||
"sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575",
|
||||
"sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a",
|
||||
"sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37",
|
||||
"sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795",
|
||||
"sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f",
|
||||
"sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32",
|
||||
"sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c",
|
||||
"sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01",
|
||||
"sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4",
|
||||
"sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2",
|
||||
"sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921",
|
||||
"sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085",
|
||||
"sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df",
|
||||
"sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102",
|
||||
"sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5",
|
||||
"sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68",
|
||||
"sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"
|
||||
"sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca",
|
||||
"sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72",
|
||||
"sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23",
|
||||
"sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8",
|
||||
"sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b",
|
||||
"sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9",
|
||||
"sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13",
|
||||
"sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75",
|
||||
"sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac",
|
||||
"sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e",
|
||||
"sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"
|
||||
],
|
||||
"markers": "python_version > '2.7'",
|
||||
"version": "==6.1"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==6.2"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
@@ -907,19 +1065,19 @@
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708",
|
||||
"sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"
|
||||
"sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02",
|
||||
"sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"
|
||||
],
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==4.2.0"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.3.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
||||
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
||||
"sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec",
|
||||
"sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.9"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'",
|
||||
"version": "==1.26.10"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
@@ -930,11 +1088,11 @@
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad",
|
||||
"sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"
|
||||
"sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2",
|
||||
"sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.8.0"
|
||||
"version": "==3.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
README.md
112
README.md
@@ -1 +1,113 @@
|
||||
# vk-url-scraper
|
||||
Python library to scrape data, and especially media links like videos and photos, from vk.com URLs.
|
||||
|
||||
|
||||
[](https://badge.fury.io/py/vk-url-scraper)
|
||||
[](https://pypi.python.org/pypi/vk-url-scraper/)
|
||||
[](https://vk-url-scraper.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
|
||||
You can use it via the [command line](#command-line-usage) or as a [python library](#python-library-usage), check the **[documentation](https://vk-url-scraper.readthedocs.io/en/latest/)**.
|
||||
|
||||
## Installation
|
||||
You can install the most recent release from [pypi](https://pypi.org/project/vk-url-scraper/) via `pip install vk-url-scraper`.
|
||||
|
||||
To use the library you will need a valid username/password combination for vk.com.
|
||||
|
||||
## Command line usage
|
||||
```bash
|
||||
# run this to learn more about the parameters
|
||||
vk_url_scraper --help
|
||||
|
||||
# scrape a URL and get the JSON result in the console
|
||||
vk_url_scraper -username "username here" --password "password here" --urls https://vk.com/wall12345_6789
|
||||
# OR
|
||||
vk_url_scraper -u "username here" -p "password here" --urls https://vk.com/wall12345_6789
|
||||
# you can also have multiple urls
|
||||
vk_url_scraper -u "username here" -p "password here" --urls https://vk.com/wall12345_6789 https://vk.com/photo-12345_6789 https://vk.com/video12345_6789
|
||||
|
||||
# you can pass a token as well to avoid always authenticating
|
||||
# and possibly getting captcha prompts
|
||||
# you can fetch the token from the bk_config.v2.json file generated under by searching for "access_token"
|
||||
vk_url_scraper -u "username" -p "password" -t "vktoken goes here" --urls https://vk.com/wall12345_6789
|
||||
|
||||
# save the JSON output into a file
|
||||
vk_url_scraper -u "username here" -p "password here" --urls https://vk.com/wall12345_6789 > output.json
|
||||
|
||||
# download any photos or videos found in these URLS
|
||||
# this will use or create an output/ folder and dump the files there
|
||||
vk_url_scraper -u "username here" -p "password here" --download --urls https://vk.com/wall12345_6789
|
||||
# or
|
||||
vk_url_scraper -u "username here" -p "password here" -d --urls https://vk.com/wall12345_6789
|
||||
```
|
||||
|
||||
## Python library usage
|
||||
```python
|
||||
from vk_url_scraper import VkScraper
|
||||
|
||||
vks = VkScraper("username", "password")
|
||||
|
||||
# scrape any "photo" URL
|
||||
res = vks.scrape("https://vk.com/photo1_278184324?rev=1")
|
||||
|
||||
# scrape any "wall" URL
|
||||
res = vks.scrape("https://vk.com/wall-1_398461")
|
||||
|
||||
# scrape any "video" URL
|
||||
res = vks.scrape("https://vk.com/video-6596301_145810025")
|
||||
print(res[0]["text"]) # eg: -> to get the text from code
|
||||
```
|
||||
|
||||
```python
|
||||
# Every scrape* function returns a list of dict like
|
||||
{
|
||||
"id": "wall_id",
|
||||
"text": "text in this post" ,
|
||||
"datetime": utc datetime of post,
|
||||
"attachments": {
|
||||
# if photo, video, link exists
|
||||
"photo": [list of urls with max quality],
|
||||
"video": [list of urls with max quality],
|
||||
"link": [list of urls with max quality],
|
||||
},
|
||||
"payload": "original JSON response converted to dict which you can parse for more data
|
||||
}
|
||||
```
|
||||
|
||||
see [docs] for all available functions.
|
||||
|
||||
### TODO
|
||||
* scrape album links
|
||||
* scrape profile links
|
||||
* docs online from sphinx
|
||||
|
||||
## Development
|
||||
(more info in [CONTRIBUTING.md](CONTRIBUTING.md)).
|
||||
|
||||
1. setup dev environment with `pip install -r dev-requirements.txt` or `pipenv install -r dev-requirements.txt`
|
||||
1. setup environment with `pip install -r requirements.txt` or `pipenv install -r requirements.txt`
|
||||
2. To run all checks to `make run-checks` (fixes style) or individually
|
||||
1. To fix style: `black .` and `isort .` -> `flake8 .` to validate lint
|
||||
2. To do type checking: `mypy .`
|
||||
3. To test: `pytest .` (`pytest -v --color=yes --doctest-modules tests/ vk_url_scraper/` to user verbose, colors, and test docstring examples)
|
||||
3. `make docs` to generate shpynx docs -> edit [config.py](docs/source/conf.py) if needed
|
||||
|
||||
To test the command line interface available in [__main__.py](__vk_url_scraper/__main__.py) you need to pass the `-m` option to python like so: `python -m vk_url_scraper -u "" -p "" --urls ...`
|
||||
|
||||
|
||||
## Releasing new version
|
||||
1. edit [version.py](vk_url_scraper/version.py) with proper versioning
|
||||
2. run `./scripts/release.sh` to create a tag and push, alternatively
|
||||
1. `git tag vx.y.z` to tag version
|
||||
2. `git push origin vx.y.z` -> this will trigger workflow and put project on [pypi](https://pypi.org/project/vk-url-scraper/)
|
||||
3. go to https://readthedocs.org/ to deploy new docs version (if webhook is not setup)
|
||||
|
||||
### Fixing a failed release
|
||||
|
||||
If for some reason the GitHub Actions release workflow failed with an error that needs to be fixed, you'll have to delete both the tag and corresponding release from GitHub. After you've pushed a fix, delete the tag from your local clone with
|
||||
|
||||
```bash
|
||||
git tag -l | xargs git tag -d && git fetch -t
|
||||
```
|
||||
|
||||
Then repeat the steps above.
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# GitHub Release Process
|
||||
|
||||
## Steps
|
||||
|
||||
1. Update the version in `vk_url_scraper/version.py`.
|
||||
|
||||
3. Run the release script:
|
||||
|
||||
```bash
|
||||
./scripts/release.sh
|
||||
```
|
||||
|
||||
This will commit the changes to the CHANGELOG and `version.py` files and then create a new tag in git
|
||||
which will trigger a workflow on GitHub Actions that handles the rest.
|
||||
|
||||
## Fixing a failed release
|
||||
|
||||
If for some reason the GitHub Actions release workflow failed with an error that needs to be fixed, you'll have to delete both the tag and corresponding release from GitHub. After you've pushed a fix, delete the tag from your local clone with
|
||||
|
||||
```bash
|
||||
git tag -l | xargs git tag -d && git fetch -t
|
||||
```
|
||||
|
||||
Then repeat the steps above.
|
||||
@@ -1 +0,0 @@
|
||||
../../CHANGELOG.md
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 7.6 KiB |
@@ -23,7 +23,6 @@ Contents
|
||||
|
||||
installation
|
||||
overview
|
||||
CHANGELOG
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -11,4 +11,5 @@ idna==3.3
|
||||
requests==2.28.0
|
||||
urllib3==1.26.9
|
||||
vk-api==11.9.8
|
||||
python-dotenv==0.20.0
|
||||
python-dotenv==0.20.0
|
||||
yt-dlp==2022.7.18
|
||||
@@ -1,39 +0,0 @@
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from vk_url_scraper.version import VERSION
|
||||
|
||||
|
||||
def main():
|
||||
changelog = Path("CHANGELOG.md")
|
||||
|
||||
with changelog.open() as f:
|
||||
lines = f.readlines()
|
||||
|
||||
insert_index: int = -1
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if line.startswith("## Unreleased"):
|
||||
insert_index = i + 1
|
||||
elif line.startswith(f"## [v{VERSION}]"):
|
||||
print("CHANGELOG already up-to-date")
|
||||
return
|
||||
elif line.startswith("## [v"):
|
||||
break
|
||||
|
||||
if insert_index < 0:
|
||||
raise RuntimeError("Couldn't find 'Unreleased' section")
|
||||
|
||||
lines.insert(insert_index, "\n")
|
||||
lines.insert(
|
||||
insert_index + 1,
|
||||
f"## [v{VERSION}](https://github.com/bellingcat/vk-url-scraper/releases/tag/v{VERSION}) - "
|
||||
f"{datetime.now().strftime('%Y-%m-%d')}\n",
|
||||
)
|
||||
|
||||
with changelog.open("w") as f:
|
||||
f.writelines(lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -7,7 +7,6 @@ TAG=$(python -c 'from vk_url_scraper.version import VERSION; print("v" + VERSION
|
||||
read -p "Creating new release for $TAG. Do you want to continue? [Y/n] " prompt
|
||||
|
||||
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]; then
|
||||
python scripts/prepare_changelog.py
|
||||
git add -A
|
||||
git commit -m "Bump version to $TAG for release" || true && git push
|
||||
echo "Creating new git tag $TAG"
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# encoding: utf-8
|
||||
|
||||
"""
|
||||
Prepares markdown release notes for GitHub releases.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
import packaging.version
|
||||
|
||||
TAG = os.environ["TAG"]
|
||||
|
||||
ADDED_HEADER = "### Added 🎉"
|
||||
CHANGED_HEADER = "### Changed ⚠️"
|
||||
FIXED_HEADER = "### Fixed ✅"
|
||||
REMOVED_HEADER = "### Removed 👋"
|
||||
|
||||
|
||||
def get_change_log_notes() -> str:
|
||||
in_current_section = False
|
||||
current_section_notes: List[str] = []
|
||||
with open("CHANGELOG.md") as changelog:
|
||||
for line in changelog:
|
||||
if line.startswith("## "):
|
||||
if line.startswith("## Unreleased"):
|
||||
continue
|
||||
if line.startswith(f"## [{TAG}]"):
|
||||
in_current_section = True
|
||||
continue
|
||||
break
|
||||
if in_current_section:
|
||||
if line.startswith("### Added"):
|
||||
line = ADDED_HEADER + "\n"
|
||||
elif line.startswith("### Changed"):
|
||||
line = CHANGED_HEADER + "\n"
|
||||
elif line.startswith("### Fixed"):
|
||||
line = FIXED_HEADER + "\n"
|
||||
elif line.startswith("### Removed"):
|
||||
line = REMOVED_HEADER + "\n"
|
||||
current_section_notes.append(line)
|
||||
assert current_section_notes
|
||||
return "## What's new\n\n" + "".join(current_section_notes).strip() + "\n"
|
||||
|
||||
|
||||
def get_commit_history() -> str:
|
||||
new_version = packaging.version.parse(TAG)
|
||||
|
||||
# Get all tags sorted by version, latest first.
|
||||
all_tags = os.popen("git tag -l --sort=-version:refname 'v*'").read().split("\n")
|
||||
|
||||
# Out of `all_tags`, find the latest previous version so that we can collect all
|
||||
# commits between that version and the new version we're about to publish.
|
||||
# Note that we ignore pre-releases unless the new version is also a pre-release.
|
||||
last_tag: Optional[str] = None
|
||||
for tag in all_tags:
|
||||
if not tag.strip(): # could be blank line
|
||||
continue
|
||||
version = packaging.version.parse(tag)
|
||||
if new_version.pre is None and version.pre is not None:
|
||||
continue
|
||||
if version < new_version:
|
||||
last_tag = tag
|
||||
break
|
||||
if last_tag is not None:
|
||||
commits = os.popen(f"git log {last_tag}..{TAG}^ --oneline --first-parent").read()
|
||||
else:
|
||||
commits = os.popen("git log --oneline --first-parent").read()
|
||||
return "## Commits\n\n" + commits
|
||||
|
||||
|
||||
def main():
|
||||
print(get_change_log_notes())
|
||||
print(get_commit_history())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
11
setup.py
11
setup.py
@@ -33,7 +33,7 @@ with open("vk_url_scraper/version.py", "r") as version_file:
|
||||
setup(
|
||||
name="vk-url-scraper",
|
||||
version=VERSION["VERSION"],
|
||||
description="",
|
||||
description="Scrape VK URLs to fetch info and media - python API or command line tool.",
|
||||
long_description=open("README.md").read(),
|
||||
long_description_content_type="text/markdown",
|
||||
classifiers=[
|
||||
@@ -43,11 +43,11 @@ setup(
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
],
|
||||
keywords="",
|
||||
keywords=["scraper", "vk", "vkontakte", "vk-api", "media-downloader"],
|
||||
url="https://github.com/bellingcat/vk-url-scraper",
|
||||
author="Bellingcat",
|
||||
author_email="tech@bellingcat.com",
|
||||
license="Apache",
|
||||
license="MIT",
|
||||
packages=find_packages(
|
||||
exclude=["*.tests", "*.tests.*", "tests.*", "tests"],
|
||||
),
|
||||
@@ -55,4 +55,9 @@ setup(
|
||||
install_requires=read_requirements("requirements.txt"),
|
||||
extras_require={"dev": read_requirements("dev-requirements.txt")},
|
||||
python_requires=">=3.7",
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"vk_url_scraper=vk_url_scraper.__main__:main",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import datetime
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from vk_url_scraper import VkScraper
|
||||
|
||||
from .util import assert_equal_lists
|
||||
|
||||
vks = None
|
||||
|
||||
|
||||
@@ -15,15 +14,38 @@ def test_login_fail():
|
||||
VkScraper("invalid", "combination")
|
||||
|
||||
|
||||
def test_login_custom_file():
|
||||
session_filename = "test-session.json"
|
||||
VkScraper(
|
||||
os.environ["VK_USERNAME"],
|
||||
os.environ["VK_PASSWORD"],
|
||||
os.environ.get("VK_TOKEN"),
|
||||
session_file=session_filename,
|
||||
)
|
||||
assert os.path.isfile(session_filename)
|
||||
os.unlink(session_filename)
|
||||
|
||||
|
||||
def test_login_success():
|
||||
global vks
|
||||
vks = VkScraper(os.environ["VK_USERNAME"], os.environ["VK_PASSWORD"])
|
||||
vks = VkScraper(
|
||||
os.environ["VK_USERNAME"], os.environ["VK_PASSWORD"], os.environ.get("VK_TOKEN")
|
||||
)
|
||||
|
||||
|
||||
def test_scrape_empty_urll():
|
||||
assert [] == vks.scrape("something")
|
||||
|
||||
|
||||
def test_scrape_no_vk_parseable_info():
|
||||
assert len(vks.scrape("")) == 0
|
||||
assert len(vks.scrape("google.com")) == 0
|
||||
assert len(vks.scrape("vk.com")) == 0
|
||||
assert len(vks.scrape("vk.com/wall")) == 0
|
||||
assert len(vks.scrape("vk.com/photo")) == 0
|
||||
assert len(vks.scrape("vk.com/video")) == 0
|
||||
|
||||
|
||||
def test_scrape_wall_url_with_text_only():
|
||||
res = vks.scrape("https://vk.com/wall-1_398461")
|
||||
assert len(res) == 1
|
||||
@@ -73,12 +95,30 @@ def test_scrape_wall_url_with_photos_inner_videos_and_links_with_inner_photos():
|
||||
assert str(res[0]["datetime"]) == str(datetime.datetime(2022, 3, 24, 11, 1, 9))
|
||||
assert len(res[0]["payload"]) == 15
|
||||
assert len(res[0]["attachments"].keys()) == 3
|
||||
assert_equal_lists(list(res[0]["attachments"].keys()), ["photo", "link", "video"])
|
||||
for k in ["photo", "link", "video"]:
|
||||
assert k in list(res[0]["attachments"].keys())
|
||||
assert len(res[0]["attachments"]["photo"]) == 5
|
||||
assert len(res[0]["attachments"]["link"]) == 1
|
||||
assert len(res[0]["attachments"]["video"]) == 1
|
||||
|
||||
|
||||
def test_scrape_download_multiple_media():
|
||||
res = vks.scrape("https://vk.com/w=wall-17315087_74182")
|
||||
|
||||
with tempfile.TemporaryDirectory(dir="./") as tempdir:
|
||||
vks.download_media(res, tempdir)
|
||||
expect_files = {
|
||||
"wall-17315087_74182_0.jpg",
|
||||
"wall-17315087_74182_1.jpg",
|
||||
"wall-17315087_74182_2.jpg",
|
||||
"wall-17315087_74182_3.jpg",
|
||||
"wall-17315087_74182_4.jpg",
|
||||
"wall-17315087_74182_0.mp4",
|
||||
}
|
||||
found_files = set(os.listdir(tempdir))
|
||||
assert len(expect_files) == len(expect_files & found_files)
|
||||
|
||||
|
||||
def test_scrape_photo_only():
|
||||
res = vks.scrape("https://vk.com/apiclub?z=photo-1_457242435%2Falbum-1_00%2Frev")
|
||||
assert len(res) == 1
|
||||
@@ -105,5 +145,8 @@ def test_scrape_video_only():
|
||||
|
||||
|
||||
def test_scrape_video_only2():
|
||||
res = vks.scrape("https://vk.com/video-1_456239018")
|
||||
print(res[0]["attachments"]["video"][0])
|
||||
res = vks.scrape("https://vk.com/video-17546758_456239898")
|
||||
with tempfile.TemporaryDirectory(dir="./") as tempdir:
|
||||
vks.download_media(res, tempdir)
|
||||
found_files = set(os.listdir(tempdir))
|
||||
assert "video-17546758_456239898_0.mp4" in found_files
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
def assert_equal_lists(l1, l2):
|
||||
assert len(l1) == len(l2)
|
||||
assert str(sorted(l1)) == str(sorted(l2))
|
||||
@@ -1 +1,2 @@
|
||||
from .scraper import VkScraper
|
||||
from .utils import DateTimeEncoder, suppress_stdout
|
||||
|
||||
71
vk_url_scraper/__main__.py
Normal file
71
vk_url_scraper/__main__.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import argparse
|
||||
import json
|
||||
|
||||
from .scraper import VkScraper
|
||||
from .utils import DateTimeEncoder
|
||||
|
||||
|
||||
def get_argument_parser():
|
||||
"""
|
||||
Creates the CMD line arguments. 'python vk_url_scraper.py --help'
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Authenticate and scrape information from vk.com based on a URL or set of URLs."
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--username",
|
||||
action="store",
|
||||
dest="username",
|
||||
required=True,
|
||||
help="username for a valid vk.com account",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--password",
|
||||
action="store",
|
||||
dest="password",
|
||||
required=True,
|
||||
help="password for the valid vk.com account",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--token",
|
||||
action="store",
|
||||
dest="token",
|
||||
required=False,
|
||||
help="optional token, when passed username/password authentication will not be done - good to avoid captcha issues",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--download",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
dest="download",
|
||||
help="if set then all photos and videos will be downloaded to folder output/",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--urls",
|
||||
action="store",
|
||||
dest="urls",
|
||||
nargs=argparse.REMAINDER,
|
||||
required=True,
|
||||
help="must be the last argument: any text with one or more urls to scrape",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
parser = get_argument_parser()
|
||||
args = parser.parse_args()
|
||||
vks = VkScraper(args.username, args.password, args.token)
|
||||
text = " ".join(args.urls)
|
||||
res = vks.scrape(text)
|
||||
res_json = json.dumps(res, ensure_ascii=False, indent=4, cls=DateTimeEncoder)
|
||||
print(res_json)
|
||||
if args.download:
|
||||
vks.download_media(res)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,22 +1,56 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
import vk_api # used to get api_token after authentication
|
||||
import yt_dlp # to download videos from url
|
||||
|
||||
from .utils import captcha_handler, suppress_stdout
|
||||
|
||||
|
||||
class VkScraper:
|
||||
"""VkScraper class that allows to authenticate and scrape URLs.
|
||||
|
||||
All `scrape*` functions return a payload like:
|
||||
|
||||
.. highlight:: python
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
"id": "wall_id",
|
||||
"text": "text in this post" ,
|
||||
"datetime": datetime of post,
|
||||
"attachments": {
|
||||
# only present values will appear, can be empty dict
|
||||
"photo": [list of urls with max quality],
|
||||
"video": [list of urls with max quality],
|
||||
"link": [list of urls with max quality],
|
||||
},
|
||||
"payload": {"more": "original JSON response as dict which you can parse for more data"}
|
||||
}
|
||||
"""
|
||||
|
||||
WALL_PATTERN = re.compile(r"(wall.{0,1}\d+_\d+)")
|
||||
PHOTO_PATTERN = re.compile(r"(photo.{0,1}\d+_\d+)")
|
||||
VIDEO_PATTERN = re.compile(r"(video.{0,1}\d+_\d+)")
|
||||
|
||||
def __init__(self, username: str, password: str, verbose: bool = True) -> None:
|
||||
"""
|
||||
Initializes the scraper.
|
||||
def __init__(
|
||||
self,
|
||||
username: str,
|
||||
password: str,
|
||||
token: str = None,
|
||||
session_file="vk_config.v2.json",
|
||||
captcha_handler=captcha_handler,
|
||||
) -> None:
|
||||
"""Initializes the scraper.
|
||||
|
||||
This function receives a username and password and performs authentication on vk.com to then call api endpoints
|
||||
This function receives a username and password (or access token) and performs
|
||||
authentication on vk.com to then call api endpoints. If token is passed, authentication will not be performed again.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -24,44 +58,67 @@ class VkScraper:
|
||||
Username on vk.com, can be a phone number or email
|
||||
password : str
|
||||
Matching password on vk.com
|
||||
verbose : bool = False
|
||||
If True will log debug info
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> VkScraper("+12345678", "password")
|
||||
token : str
|
||||
Access token received after authenticating, can be found in the vl_config.v2.json file
|
||||
session_file : str
|
||||
File name where the VK session is saved so future logins are easier
|
||||
captcha_handler : func
|
||||
Function that can receive a vk_api captcha instance and help the user solve it, default is a complete CLI handler
|
||||
"""
|
||||
self.session = vk_api.VkApi(username, password)
|
||||
self.session.auth(token_only=True)
|
||||
self.verbose = verbose
|
||||
self.session = vk_api.VkApi(
|
||||
username,
|
||||
password,
|
||||
token=token,
|
||||
config_filename=session_file,
|
||||
captcha_handler=captcha_handler,
|
||||
)
|
||||
if token is None or len(token) == 0:
|
||||
self.session.auth(token_only=True)
|
||||
|
||||
def scrape(self, url: str) -> List:
|
||||
"""Scrapes a URL for multiple possibilities of inner links such as wall, video, photo, ...
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
The URL to parse and analyze content from, typically shared from vk.com feature
|
||||
or copy-pasted from the browser
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
return self.scrape_walls(url) + self.scrape_photos(url) + self.scrape_videos(url)
|
||||
|
||||
def scrape_walls(self, url: str) -> List:
|
||||
"""Scrapes a URL for multiple wall data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
The URL to parse - should contain something like "...wall1212_3434..."
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
wall_ids = self.WALL_PATTERN.findall(url)
|
||||
return self.scrape_wall_ids(wall_ids)
|
||||
|
||||
def scrape_wall_ids(self, wall_ids: List[str], copy_history_depth: int = 2) -> List:
|
||||
def scrape_wall_ids(self, wall_ids: List[str], copy_history_depth: int = 2) -> List[dict]:
|
||||
"""
|
||||
Receives a list of wall ids like wall123123_1231
|
||||
Returns a list with one item per wall_id where each item contains:
|
||||
Receives a list of wall ids like wall123123_1231 see `api docs <https://dev.vk.com/method/wall.getById>`__
|
||||
|
||||
:returns `{
|
||||
"id": "wall_id",
|
||||
"text": "text in this post" ,
|
||||
"datetime": datetime of post,
|
||||
"attachments": {
|
||||
"photo": [list of urls with max quality],
|
||||
"album": [list of urls with max quality],
|
||||
# untested:
|
||||
# "video": [list of urls with max quality],
|
||||
# "link": [list of urls with max quality],
|
||||
},
|
||||
"payload": original response code which you can parse for more data
|
||||
}
|
||||
`
|
||||
Parameters
|
||||
----------
|
||||
wall_ids : List[str]
|
||||
list with valid wall ids like "wall123123_1231"
|
||||
copy_history_depth : int
|
||||
see `api docs <https://dev.vk.com/method/wall.getById>`__
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
if not len(wall_ids):
|
||||
return []
|
||||
@@ -134,14 +191,34 @@ class VkScraper:
|
||||
)
|
||||
return res
|
||||
|
||||
def scrape_videos(self, url: str) -> List:
|
||||
# TODO: https://vk.com/video-1_456239018
|
||||
# TODO https://vk.com/asdasdasd?w=wall-17315087_74182 has 1 video
|
||||
# https://vk.com/video38556806_456251917?list=ba2b77043648ff3789
|
||||
def scrape_videos(self, url: str) -> List[dict]:
|
||||
"""Scrapes a URL for multiple video data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
The URL to parse - should contain something like "...video1212_3434..."
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
video_ids = self.VIDEO_PATTERN.findall(url)
|
||||
return self.scrape_video_ids(video_ids)
|
||||
|
||||
def scrape_video_ids(self, video_ids: List[str]) -> List:
|
||||
def scrape_video_ids(self, video_ids: List[str]) -> List[dict]:
|
||||
"""
|
||||
Receives a list of video ids like video123123_1231 see `api docs <https://dev.vk.com/method/video.get>`__
|
||||
|
||||
Parameters
|
||||
----------
|
||||
video_ids : List[str]
|
||||
list with valid video ids like "video123123_1231"
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
if not len(video_ids):
|
||||
return []
|
||||
video_ids = [video_id.replace("video", "") for video_id in video_ids]
|
||||
@@ -170,11 +247,34 @@ class VkScraper:
|
||||
)
|
||||
return res
|
||||
|
||||
def scrape_photos(self, url: str) -> List:
|
||||
def scrape_photos(self, url: str) -> List[dict]:
|
||||
"""Scrapes a URL for multiple photo data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
The URL to parse - should contain something like "...photo1212_3434..."
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
photo_ids = self.PHOTO_PATTERN.findall(url)
|
||||
return self.scrape_photo_ids(photo_ids)
|
||||
|
||||
def scrape_photo_ids(self, photo_ids: List[str]) -> List:
|
||||
def scrape_photo_ids(self, photo_ids: List[str]) -> List[dict]:
|
||||
"""
|
||||
Receives a list of photo ids like photo123123_1231 see `api docs <https://dev.vk.com/method/photos.getById>`__
|
||||
|
||||
Parameters
|
||||
----------
|
||||
photo_ids : List[str]
|
||||
list with valid photo ids like "photo123123_1231"
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of dict as specified in the class documentation.
|
||||
"""
|
||||
if not len(photo_ids):
|
||||
return []
|
||||
photo_ids = [photo_id.replace("photo", "") for photo_id in photo_ids]
|
||||
@@ -200,3 +300,61 @@ class VkScraper:
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
def download_media(self, results: List[dict], destination: str = "./output/") -> List[str]:
|
||||
"""
|
||||
Receives a list of dicts as returned by any of the scrape* methods and downloads the URLS present
|
||||
if they are of type photo or video into the destination folder
|
||||
|
||||
Parameters
|
||||
----------
|
||||
results : List[dict]
|
||||
list with valid dictionary results (see class definition)
|
||||
destination : str
|
||||
the directory to save the downloaded files to. defaults to output/
|
||||
|
||||
Returns
|
||||
-------
|
||||
a list of filenames for the downloaded files
|
||||
"""
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
|
||||
}
|
||||
os.makedirs(destination, exist_ok=True)
|
||||
downloaded = []
|
||||
for r in results:
|
||||
for k, attachments in r["attachments"].items():
|
||||
if k == "photo":
|
||||
for i, url in enumerate(attachments):
|
||||
ext = os.path.splitext(urlparse(url).path)[1]
|
||||
filename = os.path.join(destination, f"{r['id']}_{i}{ext}")
|
||||
d = requests.get(url, headers=headers)
|
||||
with open(filename, "wb") as f:
|
||||
f.write(d.content)
|
||||
downloaded.append(filename)
|
||||
elif k == "video":
|
||||
with suppress_stdout(): # ytdlp is not 100% quiet
|
||||
for i, url in enumerate(attachments):
|
||||
filename = os.path.join(destination, f"{r['id']}_{i}.%(ext)s")
|
||||
ydl = yt_dlp.YoutubeDL(
|
||||
{
|
||||
"format": "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best",
|
||||
"merge_output_format": "mp4",
|
||||
"retries": 5,
|
||||
"noplaylist": True,
|
||||
"outtmpl": filename,
|
||||
"quiet": True,
|
||||
"restrictfilenames": True,
|
||||
"forcefilename": True,
|
||||
"simulate": False,
|
||||
}
|
||||
)
|
||||
info = ydl.extract_info(url, download=True)
|
||||
filename = ydl.prepare_filename(info)
|
||||
if "unknown_video" in filename:
|
||||
filename = shutil.copy(
|
||||
filename, filename.replace("unknown_video", "mkv")
|
||||
)
|
||||
os.remove(filename)
|
||||
downloaded.append(filename)
|
||||
return downloaded
|
||||
|
||||
33
vk_url_scraper/utils.py
Normal file
33
vk_url_scraper/utils.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DateTimeEncoder(json.JSONEncoder):
|
||||
# to allow json.dump with datetimes do json.dumps(obj, cls=DateTimeEncoder)
|
||||
def default(self, o):
|
||||
if isinstance(o, datetime):
|
||||
return str(o) # with timezone
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
def captcha_handler(captcha):
|
||||
key = input(
|
||||
f"CAPTCHA DETECTED, please solve it and input the solution. url={captcha.get_url()}:"
|
||||
).strip()
|
||||
return captcha.try_again(key)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def suppress_stdout():
|
||||
# https://thesmithfam.org/blog/2012/10/25/temporarily-suppress-console-output-in-python/
|
||||
# this is used to silence ytdlp which does not fully respects quite=True and outputs filenames to the console
|
||||
with open(os.devnull, "w") as devnull:
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = devnull
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
@@ -1,8 +1,8 @@
|
||||
_MAJOR = "0"
|
||||
_MINOR = "1"
|
||||
_MINOR = "3"
|
||||
# On main and in a nightly release the patch should be one ahead of the last
|
||||
# released build.
|
||||
_PATCH = "2"
|
||||
_PATCH = "7"
|
||||
# This is mainly for nightly builds which have the suffix ".dev$DATE". See
|
||||
# https://semver.org/#is-v123-a-semantic-version for the semantics.
|
||||
_SUFFIX = ""
|
||||
|
||||
Reference in New Issue
Block a user