mirror of
https://github.com/d0zingcat/RSSHub-python.git
synced 2026-05-14 15:09:23 +00:00
init project
This commit is contained in:
2
.coveragerc
Normal file
2
.coveragerc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[run]
|
||||||
|
source = rsshub
|
||||||
3
.flaskenv
Normal file
3
.flaskenv
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
FLASK_ENV=development
|
||||||
|
FLASK_APP=rsshub
|
||||||
|
FLASK_DEBUG=1
|
||||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.pytest_cache
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info/
|
||||||
|
.idea
|
||||||
|
venv
|
||||||
|
|
||||||
|
# Others
|
||||||
|
.vscode
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
data-dev.db
|
||||||
26
Pipfile
Normal file
26
Pipfile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.doubanio.com/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
bootstrap-flask = "*"
|
||||||
|
flask-debugtoolbar = "*"
|
||||||
|
flask-moment = "*"
|
||||||
|
Flask = "*"
|
||||||
|
python-dotenv = "*"
|
||||||
|
"psycopg2" = "*"
|
||||||
|
gunicorn = "*"
|
||||||
|
requests = "*"
|
||||||
|
parsel = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
coverage = "*"
|
||||||
|
pdir2 = "*"
|
||||||
|
ptpython = "*"
|
||||||
|
yapf = "*"
|
||||||
|
pylint = "*"
|
||||||
|
|
||||||
|
[scripts]
|
||||||
|
test = "python -m unittest discover"
|
||||||
|
coverage = "coverage run -m unittest discover"
|
||||||
456
Pipfile.lock
generated
Normal file
456
Pipfile.lock
generated
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "1a952bf63349734b6daa3bc57851614425ebe4a867ca1826881a6b0324324c27"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.doubanio.com/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"blinker": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"
|
||||||
|
],
|
||||||
|
"version": "==1.4"
|
||||||
|
},
|
||||||
|
"bootstrap-flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1f7462261b8104687807ce74b397270e7ade07c491ad7d53f215940d8433d756",
|
||||||
|
"sha256:ce5cf19c46b8d385923dc2f9ca76b92fc08c1a8d7dcb5d177325a85a94d71045"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.9"
|
||||||
|
},
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||||
|
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||||
|
],
|
||||||
|
"version": "==2018.11.29"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||||
|
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||||
|
],
|
||||||
|
"version": "==7.0"
|
||||||
|
},
|
||||||
|
"cssselect": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:066d8bc5229af09617e24b3ca4d52f1f9092d9e061931f4184cd572885c23204",
|
||||||
|
"sha256:3b5103e8789da9e936a68d993b70df732d06b8bb9a337a05ed4eb52c17ef7206"
|
||||||
|
],
|
||||||
|
"version": "==1.0.3"
|
||||||
|
},
|
||||||
|
"flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
|
||||||
|
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.2"
|
||||||
|
},
|
||||||
|
"flask-debugtoolbar": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3d9657bc0c3633ace429e3ff451742bb59d1b7a7b95c9eb23a65ac9be2812959",
|
||||||
|
"sha256:ec810083123aae0632eb32ba11e1cb4cdace81e7ce6c5009dd06c5204afbce52"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.10.1"
|
||||||
|
},
|
||||||
|
"flask-moment": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:71a601fcd5be4742227251641cb706c109680b54c5fb25c5d2ed96e576ec3b4d",
|
||||||
|
"sha256:af7ccd599d85e751ff1f7661904daa51df9950e9bc9bd4ccf174bd38ccbc401f"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.6.0"
|
||||||
|
},
|
||||||
|
"gunicorn": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
|
||||||
|
"sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==19.9.0"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||||
|
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||||
|
],
|
||||||
|
"version": "==2.8"
|
||||||
|
},
|
||||||
|
"itsdangerous": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||||
|
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||||
|
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||||
|
],
|
||||||
|
"version": "==2.10"
|
||||||
|
},
|
||||||
|
"lxml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0dd6589fa75d369ba06d2b5f38dae107f76ea127f212f6a7bee134f6df2d1d21",
|
||||||
|
"sha256:1afbac344aa68c29e81ab56c1a9411c3663157b5aee5065b7fa030b398d4f7e0",
|
||||||
|
"sha256:1baad9d073692421ad5dbbd81430aba6c7f5fdc347f03537ae046ddf2c9b2297",
|
||||||
|
"sha256:1d8736421a2358becd3edf20260e41a06a0bf08a560480d3a5734a6bcbacf591",
|
||||||
|
"sha256:1e1d9bddc5afaddf0de76246d3f2152f961697ad7439c559f179002682c45801",
|
||||||
|
"sha256:1f179dc8b2643715f020f4d119d5529b02cd794c1c8f305868b73b8674d2a03f",
|
||||||
|
"sha256:241fb7bdf97cb1df1edfa8f0bcdfd80525d4023dac4523a241907c8b2f44e541",
|
||||||
|
"sha256:2f9765ee5acd3dbdcdc0d0c79309e01f7c16bc8d39b49250bf88de7b46daaf58",
|
||||||
|
"sha256:312e1e1b1c3ce0c67e0b8105317323e12807955e8186872affb667dbd67971f6",
|
||||||
|
"sha256:3273db1a8055ca70257fd3691c6d2c216544e1a70b673543e15cc077d8e9c730",
|
||||||
|
"sha256:34dfaa8c02891f9a246b17a732ca3e99c5e42802416628e740a5d1cb2f50ff49",
|
||||||
|
"sha256:3aa3f5288af349a0f3a96448ebf2e57e17332d99f4f30b02093b7948bd9f94cc",
|
||||||
|
"sha256:51102e160b9d83c1cc435162d90b8e3c8c93b28d18d87b60c56522d332d26879",
|
||||||
|
"sha256:56115fc2e2a4140e8994eb9585119a1ae9223b506826089a3ba753a62bd194a6",
|
||||||
|
"sha256:69d83de14dbe8fe51dccfd36f88bf0b40f5debeac763edf9f8325180190eba6e",
|
||||||
|
"sha256:99fdce94aeaa3ccbdfcb1e23b34273605c5853aa92ec23d84c84765178662c6c",
|
||||||
|
"sha256:a7c0cd5b8a20f3093ee4a67374ccb3b8a126743b15a4d759e2a1bf098faac2b2",
|
||||||
|
"sha256:abe12886554634ed95416a46701a917784cb2b4c77bfacac6916681d49bbf83d",
|
||||||
|
"sha256:b4f67b5183bd5f9bafaeb76ad119e977ba570d2b0e61202f534ac9b5c33b4485",
|
||||||
|
"sha256:bdd7c1658475cc1b867b36d5c4ed4bc316be8d3368abe03d348ba906a1f83b0e",
|
||||||
|
"sha256:c6f24149a19f611a415a51b9bc5f17b6c2f698e0d6b41ffb3fa9f24d35d05d73",
|
||||||
|
"sha256:d1e111b3ab98613115a208c1017f266478b0ab224a67bc8eac670fa0bad7d488",
|
||||||
|
"sha256:d6520aa965773bbab6cb7a791d5895b00d02cf9adc93ac2bf4edb9ac1a6addc5",
|
||||||
|
"sha256:dd185cde2ccad7b649593b0cda72021bc8a91667417001dbaf24cd746ecb7c11",
|
||||||
|
"sha256:de2e5b0828a9d285f909b5d2e9d43f1cf6cf21fe65bc7660bdaa1780c7b58298",
|
||||||
|
"sha256:f726444b8e909c4f41b4fde416e1071cf28fa84634bfb4befdf400933b6463af"
|
||||||
|
],
|
||||||
|
"version": "==4.3.0"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
|
||||||
|
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
|
||||||
|
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
|
||||||
|
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
|
||||||
|
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
|
||||||
|
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
|
||||||
|
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
|
||||||
|
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
|
||||||
|
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
|
||||||
|
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
|
||||||
|
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
|
||||||
|
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
|
||||||
|
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
|
||||||
|
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
|
||||||
|
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
|
||||||
|
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
|
||||||
|
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
|
||||||
|
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
|
||||||
|
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
|
||||||
|
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
|
||||||
|
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
|
||||||
|
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
|
||||||
|
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
|
||||||
|
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
|
||||||
|
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
|
||||||
|
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
|
||||||
|
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
|
||||||
|
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"parsel": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:493a9214acbdcb4487a084d95344c25e85e90426a67311ea0425dc5df8dc24b9",
|
||||||
|
"sha256:9ccd82b8a122345601f6f9209e972c0e8c3518a188fcff2d37cb4d7bc570b4b8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.5.1"
|
||||||
|
},
|
||||||
|
"psycopg2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:10e391687b171878181e71736d0effe3772314a339d9ae30995ec8171a0c834e",
|
||||||
|
"sha256:1283f9d45e458c2dcb15ba89367923563f90ef636fe78ee22df75183484a0237",
|
||||||
|
"sha256:1a9c32e4d140bea225f9821d993b2e53c913e717ea97b851246aa9b300095d8f",
|
||||||
|
"sha256:1be6f2438d2b71fec7b07c3c0949dd321b04349c382907ea76b36120edec8300",
|
||||||
|
"sha256:20ca6f29e118b8dd7133e8708b3fba2881e70a4e0841f874ed23985b7201a076",
|
||||||
|
"sha256:227c115b3c1f65d61385e51ac690b91b584640aefb45bffacd4bd33d02ed7221",
|
||||||
|
"sha256:27959abe64ca1fc6d8cd11a71a1f421d8287831a3262bd4cacd43bbf43cc3c82",
|
||||||
|
"sha256:2b2daf1fe30a58300542aea679fd87d1e1c2afd36e7644837b7954fa2dbacb92",
|
||||||
|
"sha256:36e51a51f295fdf67bcf05e7b1877011a6b39e6622b0013fe31c5025241873a3",
|
||||||
|
"sha256:3992b9b914f2eb77dc07e8045d2ca979e491612808bc5c7cd68f307469acf9f6",
|
||||||
|
"sha256:39a11de2335ad45ececed43ab851d36a4c52843d756471b940804f301792781e",
|
||||||
|
"sha256:3c2afe9ef0d1649005e3ccf93c1aaccd6f8ee379530e763d3b3b77f406b7c0ae",
|
||||||
|
"sha256:3fb18e0e52807fe3a300dc1b5421aa492d5e759550918f597d61863419482535",
|
||||||
|
"sha256:55eab94de96ee9702f23283e9c8b03cfdb0001e2b14d5d2e1bd5ff8114b96b9f",
|
||||||
|
"sha256:7e95c0ab7e7e6e452586f35d4d8966b1e924c8dd2c23977e3ea4968770ff1d26",
|
||||||
|
"sha256:7f47514dbddf604f196fcfe5da955537f04691bef8124aff5632316a78d992b7",
|
||||||
|
"sha256:8345370356bb4bddf93acbcfd0357163dd6b09471937adcfb38a2fbb49bdce53",
|
||||||
|
"sha256:8bc6ecb220c0b88d3742042013129c817c44459795c97e9ce1bca70a3f37a53b",
|
||||||
|
"sha256:8df623f248be15d1725faf5f333791678775047f12f17a90d29b5d22573f5cdc",
|
||||||
|
"sha256:9645f1305e4268cc0fc88c823cd6c91de27c003e183c233a6a230e5e963039ee",
|
||||||
|
"sha256:a68719ed5be8373dd72c9e45d55f7a202285e05a2e392eaa8872a67ea47d7d20",
|
||||||
|
"sha256:aca0edf062ec09e954fdf0cc93d3a872362701210983a1442549e703aedec25d",
|
||||||
|
"sha256:b0dd2114d93d8f424bb8ae76e0dc540f104b70ca9163172c05e7700b1459d4c9",
|
||||||
|
"sha256:b2c09359d6802279efb9efb3f91a9c94567151baee95175f9b637ea628f35244",
|
||||||
|
"sha256:ca7bc37b1efb7cc25271bf10f398462ed975d95259af1406d38fcb268466e34f",
|
||||||
|
"sha256:e64235d9013ebf6319cb9654e08f5066112c34d8c4cc41186254ab9c3d6d5b9b",
|
||||||
|
"sha256:ec9be679c0065667503851141c31fa699e1cc69ded3ba8e5d3673dd5a6eb1370",
|
||||||
|
"sha256:eca00d0f91fcb44d88b12f1fd16ad138e38fa07debb79587e2b7ff1fe80d72b9",
|
||||||
|
"sha256:f256e807b8b2b45b6af60d7f2bb5194aab2f4acc861241c4d8ef942a55f5030d",
|
||||||
|
"sha256:fce7612a3bd6a7ba95799f88285653bf130bd7ca066b52674d5f850108b2aec0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.7.6.1"
|
||||||
|
},
|
||||||
|
"python-dotenv": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a84569d0e00d178bc5b957f7ff208bf49287cbf61857c31c258c4a91f571527b",
|
||||||
|
"sha256:c9b1ddd3cdbe75c7d462cb84674d87130f4b948f090f02c7d7144779afb99ae0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.10.1"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
||||||
|
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.21.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||||
|
],
|
||||||
|
"version": "==1.12.0"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||||
|
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||||
|
],
|
||||||
|
"version": "==1.24.1"
|
||||||
|
},
|
||||||
|
"w3lib": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:67eacd24f4f233a80bc472835ad6aad99616e49aa1d795f3dbb7b8b028fec6cf",
|
||||||
|
"sha256:e54db912ae1c79d3e246b16d3645bdf701f70ac4f8a2fc46eeb284cc02a31cd7"
|
||||||
|
],
|
||||||
|
"version": "==1.20.0"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||||
|
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
|
||||||
|
],
|
||||||
|
"version": "==0.14.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"astroid": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:35b032003d6a863f5dcd7ec11abd5cd5893428beaa31ab164982403bcb311f22",
|
||||||
|
"sha256:6a5d668d7dc69110de01cdf7aeec69a679ef486862a0850cc0fd5571505b6b7e"
|
||||||
|
],
|
||||||
|
"version": "==2.1.0"
|
||||||
|
},
|
||||||
|
"colorama": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d",
|
||||||
|
"sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"
|
||||||
|
],
|
||||||
|
"markers": "platform_system == 'Windows'",
|
||||||
|
"version": "==0.4.1"
|
||||||
|
},
|
||||||
|
"coverage": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:09e47c529ff77bf042ecfe858fb55c3e3eb97aac2c87f0349ab5a7efd6b3939f",
|
||||||
|
"sha256:0a1f9b0eb3aa15c990c328535655847b3420231af299386cfe5efc98f9c250fe",
|
||||||
|
"sha256:0cc941b37b8c2ececfed341444a456912e740ecf515d560de58b9a76562d966d",
|
||||||
|
"sha256:10e8af18d1315de936d67775d3a814cc81d0747a1a0312d84e27ae5610e313b0",
|
||||||
|
"sha256:1b4276550b86caa60606bd3572b52769860a81a70754a54acc8ba789ce74d607",
|
||||||
|
"sha256:1e8a2627c48266c7b813975335cfdea58c706fe36f607c97d9392e61502dc79d",
|
||||||
|
"sha256:2b224052bfd801beb7478b03e8a66f3f25ea56ea488922e98903914ac9ac930b",
|
||||||
|
"sha256:447c450a093766744ab53bf1e7063ec82866f27bcb4f4c907da25ad293bba7e3",
|
||||||
|
"sha256:46101fc20c6f6568561cdd15a54018bb42980954b79aa46da8ae6f008066a30e",
|
||||||
|
"sha256:4710dc676bb4b779c4361b54eb308bc84d64a2fa3d78e5f7228921eccce5d815",
|
||||||
|
"sha256:510986f9a280cd05189b42eee2b69fecdf5bf9651d4cd315ea21d24a964a3c36",
|
||||||
|
"sha256:5535dda5739257effef56e49a1c51c71f1d37a6e5607bb25a5eee507c59580d1",
|
||||||
|
"sha256:5a7524042014642b39b1fcae85fb37556c200e64ec90824ae9ecf7b667ccfc14",
|
||||||
|
"sha256:5f55028169ef85e1fa8e4b8b1b91c0b3b0fa3297c4fb22990d46ff01d22c2d6c",
|
||||||
|
"sha256:6694d5573e7790a0e8d3d177d7a416ca5f5c150742ee703f3c18df76260de794",
|
||||||
|
"sha256:6831e1ac20ac52634da606b658b0b2712d26984999c9d93f0c6e59fe62ca741b",
|
||||||
|
"sha256:77f0d9fa5e10d03aa4528436e33423bfa3718b86c646615f04616294c935f840",
|
||||||
|
"sha256:828ad813c7cdc2e71dcf141912c685bfe4b548c0e6d9540db6418b807c345ddd",
|
||||||
|
"sha256:85a06c61598b14b015d4df233d249cd5abfa61084ef5b9f64a48e997fd829a82",
|
||||||
|
"sha256:8cb4febad0f0b26c6f62e1628f2053954ad2c555d67660f28dfb1b0496711952",
|
||||||
|
"sha256:a5c58664b23b248b16b96253880b2868fb34358911400a7ba39d7f6399935389",
|
||||||
|
"sha256:aaa0f296e503cda4bc07566f592cd7a28779d433f3a23c48082af425d6d5a78f",
|
||||||
|
"sha256:ab235d9fe64833f12d1334d29b558aacedfbca2356dfb9691f2d0d38a8a7bfb4",
|
||||||
|
"sha256:b3b0c8f660fae65eac74fbf003f3103769b90012ae7a460863010539bb7a80da",
|
||||||
|
"sha256:bab8e6d510d2ea0f1d14f12642e3f35cefa47a9b2e4c7cea1852b52bc9c49647",
|
||||||
|
"sha256:c45297bbdbc8bb79b02cf41417d63352b70bcb76f1bbb1ee7d47b3e89e42f95d",
|
||||||
|
"sha256:d19bca47c8a01b92640c614a9147b081a1974f69168ecd494687c827109e8f42",
|
||||||
|
"sha256:d64b4340a0c488a9e79b66ec9f9d77d02b99b772c8b8afd46c1294c1d39ca478",
|
||||||
|
"sha256:da969da069a82bbb5300b59161d8d7c8d423bc4ccd3b410a9b4d8932aeefc14b",
|
||||||
|
"sha256:ed02c7539705696ecb7dc9d476d861f3904a8d2b7e894bd418994920935d36bb",
|
||||||
|
"sha256:ee5b8abc35b549012e03a7b1e86c09491457dba6c94112a2482b18589cc2bdb9"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.5.2"
|
||||||
|
},
|
||||||
|
"docopt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
|
||||||
|
],
|
||||||
|
"version": "==0.6.2"
|
||||||
|
},
|
||||||
|
"isort": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
|
||||||
|
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
|
||||||
|
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
|
||||||
|
],
|
||||||
|
"version": "==4.3.4"
|
||||||
|
},
|
||||||
|
"jedi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:571702b5bd167911fe9036e5039ba67f820d6502832285cde8c881ab2b2149fd",
|
||||||
|
"sha256:c8481b5e59d34a5c7c42e98f6625e633f6ef59353abea6437472c7ec2093f191"
|
||||||
|
],
|
||||||
|
"version": "==0.13.2"
|
||||||
|
},
|
||||||
|
"lazy-object-proxy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
|
||||||
|
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
|
||||||
|
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
|
||||||
|
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
|
||||||
|
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
|
||||||
|
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
|
||||||
|
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
|
||||||
|
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
|
||||||
|
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
|
||||||
|
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
|
||||||
|
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
|
||||||
|
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
|
||||||
|
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
|
||||||
|
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
|
||||||
|
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
|
||||||
|
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
|
||||||
|
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
|
||||||
|
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
|
||||||
|
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
|
||||||
|
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
|
||||||
|
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
|
||||||
|
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
|
||||||
|
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
|
||||||
|
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
|
||||||
|
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
|
||||||
|
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
|
||||||
|
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
|
||||||
|
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a",
|
||||||
|
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"
|
||||||
|
],
|
||||||
|
"version": "==1.3.1"
|
||||||
|
},
|
||||||
|
"mccabe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||||
|
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||||
|
],
|
||||||
|
"version": "==0.6.1"
|
||||||
|
},
|
||||||
|
"parso": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2",
|
||||||
|
"sha256:895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24"
|
||||||
|
],
|
||||||
|
"version": "==0.3.1"
|
||||||
|
},
|
||||||
|
"pdir2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:71761d0fe879de2c91fc36ecdb9a7f20d059deee7d94d0f10c2dea2cca1c1929",
|
||||||
|
"sha256:f3c08df2387e6d34f2ce22be78de9dd809fcffae96a69be733a4e99a2b5d8872"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.3.1.post2"
|
||||||
|
},
|
||||||
|
"prompt-toolkit": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c1d6aff5252ab2ef391c2fe498ed8c088066f66bc64a8d5c095bbf795d9fec34",
|
||||||
|
"sha256:d4c47f79b635a0e70b84fdb97ebd9a274203706b1ee5ed44c10da62755cf3ec9",
|
||||||
|
"sha256:fd17048d8335c1e6d5ee403c3569953ba3eb8555d710bfc548faf0712666ea39"
|
||||||
|
],
|
||||||
|
"version": "==2.0.7"
|
||||||
|
},
|
||||||
|
"ptpython": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:51a74abe931f692360a32d650c2ba1ca329c08f3ed9b1de8abcd1164e0b0a6a7",
|
||||||
|
"sha256:938ee050e37d61c138dbbeb21383dfef8b9ed4ffb453a5f34041f42025bf5042",
|
||||||
|
"sha256:ebe9d68ea7532ec8ab306d4bdc7ec393701cd9bbd6eff0aa3067c821f99264d4"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.0.4"
|
||||||
|
},
|
||||||
|
"pygments": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
|
||||||
|
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
|
||||||
|
],
|
||||||
|
"version": "==2.3.1"
|
||||||
|
},
|
||||||
|
"pylint": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:689de29ae747642ab230c6d37be2b969bf75663176658851f456619aacf27492",
|
||||||
|
"sha256:771467c434d0d9f081741fec1d64dfb011ed26e65e12a28fe06ca2f61c4d556c"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.2.2"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||||
|
],
|
||||||
|
"version": "==1.12.0"
|
||||||
|
},
|
||||||
|
"wcwidth": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
|
||||||
|
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
|
||||||
|
],
|
||||||
|
"version": "==0.1.7"
|
||||||
|
},
|
||||||
|
"wrapt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:e03f19f64d81d0a3099518ca26b04550026f131eced2e76ced7b85c6b8d32128"
|
||||||
|
],
|
||||||
|
"version": "==1.11.0"
|
||||||
|
},
|
||||||
|
"yapf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8aa7f9abdb97b4da4d3227306b88477982daafef0a96cc41639754ca31f46d55",
|
||||||
|
"sha256:f2df5891481f94ddadfbf8ae8ae499080752cfb06005a31bbb102f3012f8b944"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.25.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
README.md
Normal file
53
README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# RSSHub
|
||||||
|
|
||||||
|
> 🍰 万物皆可 RSS
|
||||||
|
|
||||||
|
RSSHub 是一个轻量、易于扩展的 RSS 生成器,可以给任何奇奇怪怪的内容生成 RSS 订阅源
|
||||||
|
|
||||||
|
本项目是[原RSSHub](https://github.com/DIYgod/RSSHub)的Python实现。
|
||||||
|
|
||||||
|
*其实用Python写爬虫要比JS更方便:p*
|
||||||
|
|
||||||
|
DEMO地址:https://rsshub-python.herokuapp.com
|
||||||
|
|
||||||
|
## RSS过滤
|
||||||
|
|
||||||
|
你可以通过以下查询字符串来过滤RSS的内容:
|
||||||
|
|
||||||
|
- include_title: 搜索标题
|
||||||
|
- include_description: 搜索描述
|
||||||
|
- exclude_title: 排除标题
|
||||||
|
- exclude_description: 排除描述
|
||||||
|
- limit: 限制条数
|
||||||
|
|
||||||
|
## 贡献RSS方法
|
||||||
|
|
||||||
|
1. fork这份仓库
|
||||||
|
2. 在spiders文件夹下创建新的爬虫目录和脚本,编写爬虫,参考我的[爬虫教程](https://alphardex.github.io/2018/12/15/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E7%B2%BE%E8%A6%81/)
|
||||||
|
3. 在blueprints的main.py中添加对应的路由(按照之前路由的格式)
|
||||||
|
4. 提pr
|
||||||
|
|
||||||
|
## 部署
|
||||||
|
|
||||||
|
### 搭建
|
||||||
|
|
||||||
|
首先确保安装了[pipenv](https://github.com/pypa/pipenv)
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
git clone https://github.com/alphardex/rsshub
|
||||||
|
cd rsshub
|
||||||
|
pipenv install --dev
|
||||||
|
pipenv shell
|
||||||
|
```
|
||||||
|
|
||||||
|
### 运行
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
flask run
|
||||||
|
```
|
||||||
|
|
||||||
|
### 部署到Heroku
|
||||||
|
|
||||||
|
[](https://heroku.com/deploy?template=https://github.com/alphardex/rsshub)
|
||||||
|
|
||||||
|
记得在环境变量中把FLASK_CONFIG设为production
|
||||||
9
app.json
Normal file
9
app.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "RSSHub",
|
||||||
|
"description": "A rsshub powered by flask.",
|
||||||
|
"repository": "https://github.com/alphardex/rsshub",
|
||||||
|
"keywords": [
|
||||||
|
"python",
|
||||||
|
"flask"
|
||||||
|
]
|
||||||
|
}
|
||||||
61
rsshub/__init__.py
Normal file
61
rsshub/__init__.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import os
|
||||||
|
import click
|
||||||
|
from flask import Flask, render_template
|
||||||
|
from flask.cli import with_appcontext
|
||||||
|
from rsshub.config import config
|
||||||
|
from rsshub.extensions import *
|
||||||
|
from rsshub.blueprints.main import bp as main_bp
|
||||||
|
from rsshub.utils import XMLResponse
|
||||||
|
|
||||||
|
|
||||||
|
def create_app(config_name=None):
|
||||||
|
if config_name is None:
|
||||||
|
config_name = os.getenv('FLASK_CONFIG', 'development')
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(config[config_name])
|
||||||
|
app.response_class = XMLResponse
|
||||||
|
|
||||||
|
register_blueprints(app)
|
||||||
|
register_extensions(app)
|
||||||
|
register_errors(app)
|
||||||
|
register_cli(app)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def register_extensions(app):
|
||||||
|
bootstrap.init_app(app)
|
||||||
|
debugtoolbar.init_app(app)
|
||||||
|
moment.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
|
def register_blueprints(app):
|
||||||
|
app.register_blueprint(main_bp)
|
||||||
|
|
||||||
|
|
||||||
|
def register_errors(app):
|
||||||
|
@app.errorhandler(400)
|
||||||
|
def bad_request(e):
|
||||||
|
return render_template('errors/400.html'), 400
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def page_not_found(e):
|
||||||
|
return render_template('errors/404.html'), 404
|
||||||
|
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def internal_server_error(e):
|
||||||
|
return render_template('errors/500.html'), 500
|
||||||
|
|
||||||
|
|
||||||
|
def register_cli(app):
|
||||||
|
@app.cli.command()
|
||||||
|
@with_appcontext
|
||||||
|
def ptshell():
|
||||||
|
"""Use ptpython as shell."""
|
||||||
|
try:
|
||||||
|
from ptpython.repl import embed
|
||||||
|
if not app.config['TESTING']:
|
||||||
|
embed(app.make_shell_context())
|
||||||
|
except ImportError:
|
||||||
|
click.echo('ptpython not installed! Use the default shell instead.')
|
||||||
0
rsshub/blueprints/__init__.py
Normal file
0
rsshub/blueprints/__init__.py
Normal file
46
rsshub/blueprints/main.py
Normal file
46
rsshub/blueprints/main.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from flask import Blueprint, render_template, current_app, request
|
||||||
|
|
||||||
|
|
||||||
|
bp = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('main/index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/feeds')
|
||||||
|
def feeds():
|
||||||
|
feed_rules = [rule for rule in current_app.url_map._rules if 'main' in rule.endpoint][:-2]
|
||||||
|
return render_template('main/feeds.html', rules=feed_rules)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.app_template_global()
|
||||||
|
def filter_content(ctx):
|
||||||
|
include_title = request.args.get('include_title')
|
||||||
|
include_description = request.args.get('include_description')
|
||||||
|
exclude_title = request.args.get('exclude_title')
|
||||||
|
exclude_description = request.args.get('exclude_description')
|
||||||
|
limit = request.args.get('limit', type=int)
|
||||||
|
items = ctx['items'].copy()
|
||||||
|
items = [item for item in items if include_title in item['title']] if include_title else items
|
||||||
|
items = [item for item in items if include_description in item['description']] if include_description else items
|
||||||
|
items = [item for item in items if exclude_title not in item['title']] if exclude_title else items
|
||||||
|
items = [item for item in items if exclude_description not in item['description']] if exclude_description else items
|
||||||
|
items = items[:limit] if limit else items
|
||||||
|
ctx = ctx.copy()
|
||||||
|
ctx['items'] = items
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
#---------- feed路由从这里开始 -----------#
|
||||||
|
@bp.route('/guokr/scentific')
|
||||||
|
def guokr_scientific():
|
||||||
|
from rsshub.spiders.guokr.scientific import ctx
|
||||||
|
return render_template('main/atom.xml', **filter_content(ctx))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/toutiao/today')
|
||||||
|
def toutiao_today():
|
||||||
|
from rsshub.spiders.toutiao.today import ctx
|
||||||
|
return render_template('main/atom.xml', **filter_content(ctx))
|
||||||
32
rsshub/config.py
Normal file
32
rsshub/config.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
|
||||||
|
|
||||||
|
class BaseConfig:
|
||||||
|
SITE_NAME = 'RSSHub'
|
||||||
|
GITHUB_USERNAME = 'alphardex'
|
||||||
|
EMAIL = '2582347430@qq.com'
|
||||||
|
SECRET_KEY = os.environ.get('SECRET_KEY') or 'f43hrt53et53'
|
||||||
|
DEBUG_TB_INTERCEPT_REDIRECTS = False
|
||||||
|
|
||||||
|
|
||||||
|
class DevelopmentConfig(BaseConfig):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestingConfig(BaseConfig):
|
||||||
|
TESTING = True
|
||||||
|
|
||||||
|
|
||||||
|
class ProductionConfig(BaseConfig):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
config = {
|
||||||
|
'development': DevelopmentConfig,
|
||||||
|
'testing': TestingConfig,
|
||||||
|
'production': ProductionConfig
|
||||||
|
}
|
||||||
8
rsshub/extensions.py
Normal file
8
rsshub/extensions.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from flask_bootstrap import Bootstrap
|
||||||
|
from flask_debugtoolbar import DebugToolbarExtension
|
||||||
|
from flask_moment import Moment
|
||||||
|
|
||||||
|
|
||||||
|
bootstrap = Bootstrap()
|
||||||
|
debugtoolbar = DebugToolbarExtension()
|
||||||
|
moment = Moment()
|
||||||
0
rsshub/spiders/__init__.py
Normal file
0
rsshub/spiders/__init__.py
Normal file
23
rsshub/spiders/guokr/scientific.py
Normal file
23
rsshub/spiders/guokr/scientific.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
data = requests.get(
|
||||||
|
'https://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject'
|
||||||
|
).json()['result']
|
||||||
|
|
||||||
|
|
||||||
|
def parse(d):
|
||||||
|
item = {}
|
||||||
|
item['title'] = d['title']
|
||||||
|
item['description'] = f"{d['summary']}<br><img referrerpolicy='no-referrer' src={d['image_info']['url']}"
|
||||||
|
item['pubDate'] = d['date_published']
|
||||||
|
item['link'] = d['url']
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
'title': '果壳网 科学人',
|
||||||
|
'link': 'https://www.guokr.com/scientific',
|
||||||
|
'description': '果壳网 科学人',
|
||||||
|
'author': 'alphardex',
|
||||||
|
'items': list(map(parse, data))
|
||||||
|
}
|
||||||
22
rsshub/spiders/toutiao/today.py
Normal file
22
rsshub/spiders/toutiao/today.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from rsshub.utils import fetch
|
||||||
|
|
||||||
|
base_url = 'https://toutiao.io'
|
||||||
|
tree = fetch(base_url)
|
||||||
|
items = []
|
||||||
|
posts = tree.css('.posts .post')
|
||||||
|
|
||||||
|
for post in posts:
|
||||||
|
item = {}
|
||||||
|
item['title'] = post.css('.title a::attr(title)').extract_first()
|
||||||
|
item['description'] = ''
|
||||||
|
item['pubDate'] = ''
|
||||||
|
item['link'] = base_url + post.css('.title a::attr(href)').extract_first()
|
||||||
|
items.append(item)
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
'title': '开发者头条:今日头条',
|
||||||
|
'link': 'https://toutiao.io',
|
||||||
|
'description': '开发者头条:今日头条',
|
||||||
|
'author': 'alphardex',
|
||||||
|
'items': items
|
||||||
|
}
|
||||||
48
rsshub/static/css/style.css
Normal file
48
rsshub/static/css/style.css
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* global */
|
||||||
|
|
||||||
|
nav {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbotron {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 38px;
|
||||||
|
padding-bottom: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
/* from github.com */
|
||||||
|
position: relative;
|
||||||
|
padding: 40px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #fafbfc;
|
||||||
|
border: 1px solid #e1e4e8;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: inset 0 0 10px rgba(27, 31, 35, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer {
|
||||||
|
padding-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* footer */
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin: 30px 0;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
BIN
rsshub/static/favicon.ico
Normal file
BIN
rsshub/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
9
rsshub/templates/errors/400.html
Normal file
9
rsshub/templates/errors/400.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block title %}400 错误{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>400 Bad Request</h1>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
9
rsshub/templates/errors/404.html
Normal file
9
rsshub/templates/errors/404.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block title %}404 错误{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>404 Not Found</h1>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
9
rsshub/templates/errors/500.html
Normal file
9
rsshub/templates/errors/500.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block title %}500 错误{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>服务器出错</h1>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
69
rsshub/templates/layout.html
Normal file
69
rsshub/templates/layout.html
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{% from 'bootstrap/nav.html' import render_nav_item %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<title>{% block title %}{% endblock title %}</title>
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||||||
|
{% block styles %}
|
||||||
|
{{ bootstrap.load_css() }}
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
|
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
{% endblock styles %}
|
||||||
|
{% endblock head %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{% block nav %}
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="{{url_for('main.index')}}">{{ config['SITE_NAME'] }}</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown"
|
||||||
|
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNavDropdown">
|
||||||
|
<ul class="nav navbar-nav ml-auto">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock nav %}
|
||||||
|
<main class="container">
|
||||||
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for category, message in messages %}
|
||||||
|
<div class="alert alert-dismissable alert-{{ category }}" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
<footer>
|
||||||
|
<p class="float-left">
|
||||||
|
<small>©
|
||||||
|
Made by <a href="https://github.com/{{config['GITHUB_USERNAME']}}" target="_blank">{{config['GITHUB_USERNAME']}}</a>
|
||||||
|
with <span class="fa fa-heart"></span>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<p class="float-right">
|
||||||
|
<small><a href="mailto:{{ config['EMAIL'] }}">Contact</a></small>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
{% endblock footer %}
|
||||||
|
</main>
|
||||||
|
{% block scripts %}
|
||||||
|
{{ bootstrap.load_js() }}
|
||||||
|
{{ moment.include_moment() }}
|
||||||
|
{{ moment.locale('zh-cn') }}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
22
rsshub/templates/main/atom.xml
Normal file
22
rsshub/templates/main/atom.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||||
|
<generator>{{config['SITE_NAME']}}</generator>
|
||||||
|
<webMaster>{{config['EMAIL']}}</webMaster>
|
||||||
|
<language>zh-cn</language>
|
||||||
|
<id>{{link}}</id>
|
||||||
|
<title><![CDATA[{{title|safe}}]]></title>
|
||||||
|
<link href="{{link}}"/>
|
||||||
|
<author>
|
||||||
|
<name><![CDATA[{{author|safe}}]]></name>
|
||||||
|
</author>
|
||||||
|
{% for item in items %}
|
||||||
|
<entry>
|
||||||
|
<id>{{item.link}}</id>
|
||||||
|
<title><![CDATA[{{item.title|safe}}]]></title>
|
||||||
|
<published>{{item.pubDate}}</published>
|
||||||
|
<updated>{{item.pubDate}}</updated>
|
||||||
|
<link href="{{item.link}}"/>
|
||||||
|
<content type="html" src="{{item.link}}"><![CDATA[{{item.description|safe}}]]></content>
|
||||||
|
</entry>
|
||||||
|
{% endfor %}
|
||||||
|
</feed>
|
||||||
11
rsshub/templates/main/feeds.html
Normal file
11
rsshub/templates/main/feeds.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block title %}All Feeds{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="list-group">
|
||||||
|
{% for rule in rules %}
|
||||||
|
<a href="{{rule.rule}}" class="list-group-item list-group-item-action">{{rule.endpoint[5:]}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
13
rsshub/templates/main/index.html
Normal file
13
rsshub/templates/main/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block title %}Welcome to RSShub!{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1 class="display-4">Welcome to RSSHub!</h1>
|
||||||
|
<p class="lead">If you see this page, the RSSHub is successfully installed and working.</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-primary btn-lg" role="button" href="{{url_for('main.feeds')}}">View All Feeds</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
25
rsshub/utils.py
Normal file
25
rsshub/utils.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from flask import Response
|
||||||
|
import requests
|
||||||
|
from parsel import Selector
|
||||||
|
|
||||||
|
DEFAULT_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
|
||||||
|
|
||||||
|
|
||||||
|
class XMLResponse(Response):
|
||||||
|
def __init__(self, response, **kwargs):
|
||||||
|
if 'mimetype' not in kwargs and 'contenttype' not in kwargs:
|
||||||
|
if response.startswith('<?xml'):
|
||||||
|
kwargs['mimetype'] = 'application/xml'
|
||||||
|
return super().__init__(response, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch(url: str, headers: dict=DEFAULT_HEADERS, proxies: dict=None):
|
||||||
|
try:
|
||||||
|
res = requests.get(url, headers=headers, proxies=proxies)
|
||||||
|
res.raise_for_status()
|
||||||
|
except Exception as e:
|
||||||
|
print(f'[Err] {e}')
|
||||||
|
else:
|
||||||
|
html = res.text
|
||||||
|
tree = Selector(text=html)
|
||||||
|
return tree
|
||||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
15
tests/base.py
Normal file
15
tests/base.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import unittest
|
||||||
|
from flask import url_for
|
||||||
|
from rsshub import create_app
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
app = create_app('testing')
|
||||||
|
self.context = app.test_request_context()
|
||||||
|
self.context.push()
|
||||||
|
self.client = app.test_client()
|
||||||
|
self.runner = app.test_cli_runner()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.context.pop()
|
||||||
7
tests/test_cli.py
Normal file
7
tests/test_cli.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestCase(BaseTestCase):
|
||||||
|
def test_ptshell(self):
|
||||||
|
result = self.runner.invoke(args=['ptshell'])
|
||||||
|
self.assertNotIn('ptpython not installed! Use the default shell instead.', result.output)
|
||||||
30
tests/test_errors.py
Normal file
30
tests/test_errors.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from flask import current_app, abort
|
||||||
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorsTestCase(BaseTestCase):
|
||||||
|
def test_400(self):
|
||||||
|
@current_app.route('/400')
|
||||||
|
def bad_request():
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
response = self.client.get('/400')
|
||||||
|
data = response.get_data(as_text=True)
|
||||||
|
self.assertIn('400 Bad Request', data)
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
|
def test_404(self):
|
||||||
|
response = self.client.get('/nothing')
|
||||||
|
data = response.get_data(as_text=True)
|
||||||
|
self.assertIn('404 Not Found', data)
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_500(self):
|
||||||
|
@current_app.route('/500')
|
||||||
|
def internal_server_error_for_test():
|
||||||
|
abort(500)
|
||||||
|
|
||||||
|
response = self.client.get('/500')
|
||||||
|
data = response.get_data(as_text=True)
|
||||||
|
self.assertIn('服务器出错', data)
|
||||||
|
self.assertEqual(response.status_code, 500)
|
||||||
8
tests/test_main.py
Normal file
8
tests/test_main.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from flask import url_for
|
||||||
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class MainTestCase(BaseTestCase):
|
||||||
|
def test_index(self):
|
||||||
|
response = self.client.get(url_for('main.index'))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
Reference in New Issue
Block a user