commit d9f4136fa41cd0e6d1e357f3bed2ba82eb3dab17 Author: alphardex <2582347430@qq.com> Date: Wed Jan 16 22:45:05 2019 +0800 init project diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..f32ec8f --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +source = rsshub \ No newline at end of file diff --git a/.flaskenv b/.flaskenv new file mode 100644 index 0000000..c40645d --- /dev/null +++ b/.flaskenv @@ -0,0 +1,3 @@ +FLASK_ENV=development +FLASK_APP=rsshub +FLASK_DEBUG=1 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60bba3f --- /dev/null +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..612bf87 --- /dev/null +++ b/Pipfile @@ -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" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..58e3a40 --- /dev/null +++ b/Pipfile.lock @@ -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" + } + } +} diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..efae4d8 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: flask db upgrade; gunicorn wsgi:app \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d6824c --- /dev/null +++ b/README.md @@ -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 + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/alphardex/rsshub) + +记得在环境变量中把FLASK_CONFIG设为production diff --git a/app.json b/app.json new file mode 100644 index 0000000..edb9eba --- /dev/null +++ b/app.json @@ -0,0 +1,9 @@ +{ + "name": "RSSHub", + "description": "A rsshub powered by flask.", + "repository": "https://github.com/alphardex/rsshub", + "keywords": [ + "python", + "flask" + ] +} \ No newline at end of file diff --git a/rsshub/__init__.py b/rsshub/__init__.py new file mode 100644 index 0000000..33e0dc9 --- /dev/null +++ b/rsshub/__init__.py @@ -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.') diff --git a/rsshub/blueprints/__init__.py b/rsshub/blueprints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rsshub/blueprints/main.py b/rsshub/blueprints/main.py new file mode 100644 index 0000000..de27650 --- /dev/null +++ b/rsshub/blueprints/main.py @@ -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)) diff --git a/rsshub/config.py b/rsshub/config.py new file mode 100644 index 0000000..da9b0bb --- /dev/null +++ b/rsshub/config.py @@ -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 +} diff --git a/rsshub/extensions.py b/rsshub/extensions.py new file mode 100644 index 0000000..3d5cc33 --- /dev/null +++ b/rsshub/extensions.py @@ -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() diff --git a/rsshub/spiders/__init__.py b/rsshub/spiders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rsshub/spiders/guokr/scientific.py b/rsshub/spiders/guokr/scientific.py new file mode 100644 index 0000000..4911352 --- /dev/null +++ b/rsshub/spiders/guokr/scientific.py @@ -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']}
+

400 Bad Request

+ +{% endblock %} \ No newline at end of file diff --git a/rsshub/templates/errors/404.html b/rsshub/templates/errors/404.html new file mode 100644 index 0000000..9480d26 --- /dev/null +++ b/rsshub/templates/errors/404.html @@ -0,0 +1,9 @@ +{% extends 'layout.html' %} + +{% block title %}404 错误{% endblock %} + +{% block content %} +
+

404 Not Found

+
+{% endblock %} \ No newline at end of file diff --git a/rsshub/templates/errors/500.html b/rsshub/templates/errors/500.html new file mode 100644 index 0000000..8e4546a --- /dev/null +++ b/rsshub/templates/errors/500.html @@ -0,0 +1,9 @@ +{% extends 'layout.html' %} + +{% block title %}500 错误{% endblock %} + +{% block content %} +
+

服务器出错

+
+{% endblock %} \ No newline at end of file diff --git a/rsshub/templates/layout.html b/rsshub/templates/layout.html new file mode 100644 index 0000000..34678ba --- /dev/null +++ b/rsshub/templates/layout.html @@ -0,0 +1,69 @@ +{% from 'bootstrap/nav.html' import render_nav_item %} + + + + + {% block head %} + + + {% block title %}{% endblock title %} + + + {% block styles %} + {{ bootstrap.load_css() }} + + + {% endblock styles %} + {% endblock head %} + + + + {% block nav %} + + {% endblock nav %} +
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + {% block content %}{% endblock %} + {% block footer %} + + {% endblock footer %} +
+ {% block scripts %} + {{ bootstrap.load_js() }} + {{ moment.include_moment() }} + {{ moment.locale('zh-cn') }} + {% endblock %} + + + \ No newline at end of file diff --git a/rsshub/templates/main/atom.xml b/rsshub/templates/main/atom.xml new file mode 100644 index 0000000..017b7f8 --- /dev/null +++ b/rsshub/templates/main/atom.xml @@ -0,0 +1,22 @@ + + + {{config['SITE_NAME']}} + {{config['EMAIL']}} + zh-cn + {{link}} + <![CDATA[{{title|safe}}]]> + + + + + {% for item in items %} + + {{item.link}} + <![CDATA[{{item.title|safe}}]]> + {{item.pubDate}} + {{item.pubDate}} + + + + {% endfor %} + \ No newline at end of file diff --git a/rsshub/templates/main/feeds.html b/rsshub/templates/main/feeds.html new file mode 100644 index 0000000..88e808a --- /dev/null +++ b/rsshub/templates/main/feeds.html @@ -0,0 +1,11 @@ +{% extends "layout.html" %} + +{% block title %}All Feeds{% endblock title %} + +{% block content %} +
+ {% for rule in rules %} + {{rule.endpoint[5:]}} + {% endfor %} +
+{% endblock content %} \ No newline at end of file diff --git a/rsshub/templates/main/index.html b/rsshub/templates/main/index.html new file mode 100644 index 0000000..95dca1d --- /dev/null +++ b/rsshub/templates/main/index.html @@ -0,0 +1,13 @@ +{% extends 'layout.html' %} + +{% block title %}Welcome to RSShub!{% endblock title %} + +{% block content %} +
+

Welcome to RSSHub!

+

If you see this page, the RSSHub is successfully installed and working.

+

+ View All Feeds +

+
+{% endblock %} \ No newline at end of file diff --git a/rsshub/utils.py b/rsshub/utils.py new file mode 100644 index 0000000..b1cd5e8 --- /dev/null +++ b/rsshub/utils.py @@ -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('