├── .gitignore ├── .env.example ├── Pipfile ├── scrapy.cfg ├── LICENSE ├── README.md ├── checker.py └── Pipfile.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | CLALIT_USER_ID= 2 | CLALIT_USER_NAME= 3 | CLALIT_PASSWORD= 4 | GMAIL_USERNAME= 5 | GMAIL_PASSWORD= 6 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | scrapy = "*" 8 | python-dotenv = "*" 9 | 10 | [dev-packages] 11 | 12 | [requires] 13 | python_version = "3.9" 14 | 15 | [scripts] 16 | checker = "python checker.py" 17 | -------------------------------------------------------------------------------- /scrapy.cfg: -------------------------------------------------------------------------------- 1 | # Automatically created by: scrapy startproject 2 | # 3 | # For more information about the [deploy] section see: 4 | # https://scrapyd.readthedocs.io/en/latest/deploy.html 5 | 6 | [settings] 7 | default = clalitapptchecker.settings 8 | 9 | [deploy] 10 | #url = http://localhost:6800/ 11 | project = clalitapptchecker 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dekel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clalit-appt-checker 2 | Python scraper to check for earlier appointments in Clalit Health Services 3 | 4 | ## Some background 5 | If you ever needed to schedule a doctor's appointment at Clalit you probably noticed that most available slots are a few months ah 6 | ead, and it's not that easy to find a slot for "next week" (sometimes not even two weeks from now). There is a "waiting list", but 7 | it's based on someone from Clalit calling you to re-schedule your appointment (and it usually doesn't really work). 8 | Sometimes people cancel their appointments, but in order to catch a better slot - you need to sign in to the website and look for 9 | a newer slot. Over and over again. 10 | 11 | So basically this is what this script does for me. 12 | 13 | It will not change your appointment, but will let you know (by mail) that there is a newer slot available. 14 | 15 | ## How to run 16 | 1. Make sure you have pipenv installed 17 | 2. Run `pipenv install` to install all python dependencies 18 | 3. Copy the sample env file and set the relevant values inside `cp .env.example .env` 19 | 4. Run `pipenv run checker` to execute the checker script 20 | 21 | ## Set as cronjob 22 | `*/15 * * * * cd /PATH/TO/clalit-appt-checker && /usr/local/bin/pipenv run checker >/tmp/cronstdout.log 2>/tmp/cronstderr.log` 23 | This will run the script on every 15th minute of the hour (00:00, 00:15, 00:30, 00:45, 01:00 ...) 24 | 25 | ## Send mails using gmail 26 | In order to send emails using SMTP with gmail you will need to configure your gmail account to allow less secure apps amd setup an App password 27 | -------------------------------------------------------------------------------- /checker.py: -------------------------------------------------------------------------------- 1 | from scrapy.signalmanager import dispatcher 2 | from scrapy.crawler import CrawlerProcess 3 | from scrapy import signals 4 | import scrapy 5 | import json 6 | import datetime 7 | import smtplib 8 | from dotenv import load_dotenv 9 | import os 10 | 11 | load_dotenv() 12 | 13 | 14 | def send_dates_by_mail(dates): 15 | if not dates: 16 | return 17 | 18 | smtpclient = smtplib.SMTP(host="smtp.gmail.com", port=587) 19 | smtpclient.starttls() 20 | smtpclient.login(os.getenv('GMAIL_USERNAME'), os.getenv('GMAIL_PASSWORD')) 21 | msg = "From: me@localhost\n" \ 22 | "Subject: Dates found\n\n" 23 | 24 | msg += "\n".join(["{} - {}".format(x['profession_name'], x['date']) for x in dates]) 25 | 26 | smtpclient.sendmail("me@localhost", [os.getenv('GMAIL_USERNAME')], msg.encode('utf8')) 27 | 28 | 29 | class ClalitChecker(scrapy.Spider): 30 | name = "Clalit Checker" 31 | login_url = "https://e-services.clalit.co.il/OnlineWeb/General/Login.aspx" 32 | appointments_url = "https://e-services.clalit.co.il/OnlineWeb/Services/Tamuz/TamuzTransfer.aspx" 33 | appointments_iframe_url = "https://e-services.clalit.co.il/OnlineWeb/Services/Tamuz/TamuzTransferContentByService" \ 34 | ".aspx?MethodName=TransferWithAuth" 35 | appointments_iframe_login_url = "https://e-services.clalit.co.il/Zimunet/Visits/Login" 36 | appointment_url = "https://e-services.clalit.co.il/Zimunet/AvailableVisit/GetMonthlyAvailableVisit?id={}&" \ 37 | "professionType=Professional&month={}&year={}&isUpdateVisit=True" 38 | 39 | def parse(self, response, **kwargs): 40 | appointments = [ 41 | (visit.attrib['data-id'], 42 | datetime.datetime.strptime(visit.css("span.visitDateTime")[0].root.text, "%d.%m.%Y"), 43 | visit.css("div.professionName")[0].root.text 44 | ) 45 | for visit in response.css("#visits li.visit") if 'data-id' in visit.attrib 46 | ] 47 | month = datetime.datetime.now().month 48 | year = datetime.datetime.now().year 49 | 50 | return [scrapy.FormRequest(url=self.appointment_url.format(appointment, month, year), 51 | cb_kwargs=dict( 52 | appointment=appointment, 53 | month=month, 54 | year=year, 55 | original_date=original_date, 56 | profession_name=professionName, 57 | ), 58 | callback=self.handle_appointments) 59 | for appointment, original_date, professionName in appointments] 60 | 61 | def handle_appointments(self, response, appointment, month, year, original_date, profession_name): 62 | if response.body: 63 | data = json.loads(response.body) 64 | if data['errorType'] == 0: 65 | for d in data['data']['availableDays']: 66 | if datetime.datetime.strptime(d, "%d.%m.%Y") < original_date: 67 | yield {"date": d, "profession_name": profession_name} 68 | 69 | elif data['errorType'] == 1: 70 | next_month = month == 12 and 1 or month + 1 71 | next_year = month == 12 and year + 1 or year 72 | if datetime.datetime.strptime("{}.{}.{}".format(1, next_month, next_year), "%d.%m.%Y") < original_date: 73 | yield scrapy.FormRequest(url=self.appointment_url.format(appointment, next_month, next_year), 74 | cb_kwargs=dict( 75 | appointment=appointment, 76 | month=next_month, 77 | year=next_year, 78 | original_date=original_date, 79 | profession_name=profession_name, 80 | ), 81 | callback=self.handle_appointments) 82 | 83 | elif data['errorType'] == 3: 84 | self.logger.error("There was an error in Clalit's website") 85 | 86 | def start_requests(self): 87 | return [scrapy.Request(self.login_url, callback=self.handle_login)] 88 | 89 | def handle_login(self, response): 90 | form_data = {x.attrib['name']: x.attrib['value'] if 'value' in x.attrib else '' for x in response.css('input')} 91 | 92 | form_data['ctl00$cphBody$_loginView$tbUserId'] = os.getenv('CLALIT_USER_ID') 93 | form_data['ctl00$cphBody$_loginView$tbUserName'] = os.getenv('CLALIT_USER_NAME') 94 | form_data['ctl00$cphBody$_loginView$tbPassword'] = os.getenv('CLALIT_PASSWORD') 95 | form_data['__EVENTTARGET'] = "ctl00$cphBody$_loginView$btnSend" 96 | 97 | inputs_to_remove = ['ctl00$cphBody$_loginView$imgHelpUserId', 'ctl00$cphBody$_loginView$imgHelpUserName', 98 | 'ctl00$cphBody$_loginView$imgHelpPassword', 'ctl00$cphBody$_loginView$imgHelpCaptcha', 99 | 'ctl00$mdModalDialogNonSecureMatser$MyButtonCtrl'] 100 | 101 | for input_to_remove in inputs_to_remove: 102 | del form_data[input_to_remove] 103 | 104 | return scrapy.FormRequest(url=self.login_url, method="POST", formdata=form_data, callback=self.after_login) 105 | 106 | def after_login(self, response): 107 | if not response.url.endswith("FamilyHomePage.aspx"): 108 | raise Exception("login didn't work") 109 | 110 | return scrapy.Request(self.appointments_url, callback=self.handle_iframe) 111 | 112 | def handle_iframe(self, response): 113 | return scrapy.Request(self.appointments_iframe_url, callback=self.handle_iframe_login) 114 | 115 | def handle_iframe_login(self, response): 116 | form_data = {x.attrib['name']: x.attrib['value'] if 'value' in x.attrib else '' for x in response.css('input')} 117 | return scrapy.FormRequest(url=self.appointments_iframe_login_url, method="POST", formdata=form_data) 118 | 119 | 120 | if __name__ == "__main__": 121 | results = [] 122 | 123 | def crawler_results(signal, sender, item, response, spider): 124 | results.append(item) 125 | 126 | dispatcher.connect(crawler_results, signal=signals.item_passed) 127 | process = CrawlerProcess(settings={ 128 | "USER_AGENT": 'Mozilla/5.0 (Android 10; Mobile; rv:88.0) Gecko/88.0 Firefox/88.0' 129 | }) 130 | process.crawl(ClalitChecker) 131 | process.start() 132 | 133 | if os.getenv('GMAIL_USERNAME'): 134 | send_dates_by_mail(results) 135 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "7b1847d72e3bb95330b7294fdf5fda02900d7d226a38fb1407863dfc4fe02390" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "attrs": { 20 | "hashes": [ 21 | "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", 22 | "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" 23 | ], 24 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 25 | "version": "==21.2.0" 26 | }, 27 | "automat": { 28 | "hashes": [ 29 | "sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33", 30 | "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111" 31 | ], 32 | "version": "==20.2.0" 33 | }, 34 | "cffi": { 35 | "hashes": [ 36 | "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", 37 | "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373", 38 | "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69", 39 | "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f", 40 | "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", 41 | "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05", 42 | "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", 43 | "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", 44 | "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0", 45 | "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", 46 | "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7", 47 | "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f", 48 | "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", 49 | "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", 50 | "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76", 51 | "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", 52 | "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", 53 | "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed", 54 | "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", 55 | "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", 56 | "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", 57 | "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", 58 | "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", 59 | "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", 60 | "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", 61 | "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55", 62 | "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", 63 | "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", 64 | "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", 65 | "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", 66 | "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", 67 | "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", 68 | "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", 69 | "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", 70 | "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", 71 | "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", 72 | "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", 73 | "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", 74 | "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", 75 | "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", 76 | "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", 77 | "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", 78 | "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", 79 | "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc", 80 | "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", 81 | "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", 82 | "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333", 83 | "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", 84 | "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" 85 | ], 86 | "version": "==1.14.5" 87 | }, 88 | "constantly": { 89 | "hashes": [ 90 | "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35", 91 | "sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d" 92 | ], 93 | "version": "==15.1.0" 94 | }, 95 | "cryptography": { 96 | "hashes": [ 97 | "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d", 98 | "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959", 99 | "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6", 100 | "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873", 101 | "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2", 102 | "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713", 103 | "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1", 104 | "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177", 105 | "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250", 106 | "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca", 107 | "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d", 108 | "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9" 109 | ], 110 | "markers": "python_version >= '3.6'", 111 | "version": "==3.4.7" 112 | }, 113 | "cssselect": { 114 | "hashes": [ 115 | "sha256:f612ee47b749c877ebae5bb77035d8f4202c6ad0f0fc1271b3c18ad6c4468ecf", 116 | "sha256:f95f8dedd925fd8f54edb3d2dfb44c190d9d18512377d3c1e2388d16126879bc" 117 | ], 118 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 119 | "version": "==1.1.0" 120 | }, 121 | "h2": { 122 | "hashes": [ 123 | "sha256:61e0f6601fa709f35cdb730863b4e5ec7ad449792add80d1410d4174ed139af5", 124 | "sha256:875f41ebd6f2c44781259005b157faed1a5031df3ae5aa7bcb4628a6c0782f14" 125 | ], 126 | "version": "==3.2.0" 127 | }, 128 | "hpack": { 129 | "hashes": [ 130 | "sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89", 131 | "sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2" 132 | ], 133 | "version": "==3.0.0" 134 | }, 135 | "hyperframe": { 136 | "hashes": [ 137 | "sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40", 138 | "sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f" 139 | ], 140 | "version": "==5.2.0" 141 | }, 142 | "hyperlink": { 143 | "hashes": [ 144 | "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b", 145 | "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4" 146 | ], 147 | "version": "==21.0.0" 148 | }, 149 | "idna": { 150 | "hashes": [ 151 | "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", 152 | "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" 153 | ], 154 | "markers": "python_version >= '3.5'", 155 | "version": "==3.2" 156 | }, 157 | "incremental": { 158 | "hashes": [ 159 | "sha256:02f5de5aff48f6b9f665d99d48bfc7ec03b6e3943210de7cfc88856d755d6f57", 160 | "sha256:92014aebc6a20b78a8084cdd5645eeaa7f74b8933f70fa3ada2cfbd1e3b54321" 161 | ], 162 | "version": "==21.3.0" 163 | }, 164 | "itemadapter": { 165 | "hashes": [ 166 | "sha256:5327c2136353cb965b6b4ba564af002fd458691b8e30d3bd6b14c474d92c6b25", 167 | "sha256:cb7aaa577fefe2aa6f229ccf4d058e05f44e0178a98c8fb70ee4d95acfabb423" 168 | ], 169 | "markers": "python_version >= '3.6'", 170 | "version": "==0.2.0" 171 | }, 172 | "itemloaders": { 173 | "hashes": [ 174 | "sha256:1277cd8ca3e4c02dcdfbc1bcae9134ad89acfa6041bd15b4561c6290203a0c96", 175 | "sha256:4cb46a0f8915e910c770242ae3b60b1149913ed37162804f1e40e8535d6ec497" 176 | ], 177 | "markers": "python_version >= '3.6'", 178 | "version": "==1.0.4" 179 | }, 180 | "jmespath": { 181 | "hashes": [ 182 | "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9", 183 | "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f" 184 | ], 185 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 186 | "version": "==0.10.0" 187 | }, 188 | "lxml": { 189 | "hashes": [ 190 | "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d", 191 | "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3", 192 | "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2", 193 | "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae", 194 | "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f", 195 | "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927", 196 | "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3", 197 | "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7", 198 | "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59", 199 | "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f", 200 | "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade", 201 | "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96", 202 | "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468", 203 | "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b", 204 | "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4", 205 | "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354", 206 | "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83", 207 | "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04", 208 | "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16", 209 | "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791", 210 | "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a", 211 | "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51", 212 | "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1", 213 | "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a", 214 | "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f", 215 | "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee", 216 | "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec", 217 | "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969", 218 | "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28", 219 | "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a", 220 | "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa", 221 | "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106", 222 | "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d", 223 | "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617", 224 | "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4", 225 | "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92", 226 | "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0", 227 | "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4", 228 | "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24", 229 | "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2", 230 | "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e", 231 | "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0", 232 | "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654", 233 | "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2", 234 | "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23", 235 | "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586" 236 | ], 237 | "markers": "platform_python_implementation == 'CPython'", 238 | "version": "==4.6.3" 239 | }, 240 | "parsel": { 241 | "hashes": [ 242 | "sha256:70efef0b651a996cceebc69e55a85eb2233be0890959203ba7c3a03c72725c79", 243 | "sha256:9e1fa8db1c0b4a878bf34b35c043d89c9d1cbebc23b4d34dbc3c0ec33f2e087d" 244 | ], 245 | "version": "==1.6.0" 246 | }, 247 | "priority": { 248 | "hashes": [ 249 | "sha256:6bc1961a6d7fcacbfc337769f1a382c8e746566aaa365e78047abe9f66b2ffbe", 250 | "sha256:be4fcb94b5e37cdeb40af5533afe6dd603bd665fe9c8b3052610fc1001d5d1eb" 251 | ], 252 | "version": "==1.3.0" 253 | }, 254 | "protego": { 255 | "hashes": [ 256 | "sha256:a682771bc7b51b2ff41466460896c1a5a653f9a1e71639ef365a72e66d8734b4" 257 | ], 258 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 259 | "version": "==0.1.16" 260 | }, 261 | "pyasn1": { 262 | "hashes": [ 263 | "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", 264 | "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", 265 | "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", 266 | "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", 267 | "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", 268 | "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", 269 | "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", 270 | "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", 271 | "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", 272 | "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", 273 | "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", 274 | "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", 275 | "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" 276 | ], 277 | "version": "==0.4.8" 278 | }, 279 | "pyasn1-modules": { 280 | "hashes": [ 281 | "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", 282 | "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", 283 | "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", 284 | "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", 285 | "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", 286 | "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", 287 | "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", 288 | "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", 289 | "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", 290 | "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", 291 | "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", 292 | "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", 293 | "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" 294 | ], 295 | "version": "==0.2.8" 296 | }, 297 | "pycparser": { 298 | "hashes": [ 299 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 300 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 301 | ], 302 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 303 | "version": "==2.20" 304 | }, 305 | "pydispatcher": { 306 | "hashes": [ 307 | "sha256:5570069e1b1769af1fe481de6dd1d3a388492acddd2cdad7a3bde145615d5caf", 308 | "sha256:5be4a8be12805ef7d712dd9a93284fb8bc53f309867e573f653a72e5fd10e433" 309 | ], 310 | "markers": "platform_python_implementation == 'CPython'", 311 | "version": "==2.0.5" 312 | }, 313 | "pyopenssl": { 314 | "hashes": [ 315 | "sha256:4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51", 316 | "sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b" 317 | ], 318 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 319 | "version": "==20.0.1" 320 | }, 321 | "python-dotenv": { 322 | "hashes": [ 323 | "sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544", 324 | "sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f" 325 | ], 326 | "index": "pypi", 327 | "version": "==0.17.1" 328 | }, 329 | "queuelib": { 330 | "hashes": [ 331 | "sha256:631d067c9be57e395c382d680d3653ca1452cd29e8da25c5e8d94b5c0c528c31", 332 | "sha256:90ee30ebb0b57112606358b63c09a681bbb9a7dd1120af09c836b475504cea85" 333 | ], 334 | "version": "==1.6.1" 335 | }, 336 | "scrapy": { 337 | "hashes": [ 338 | "sha256:0a68ed41f7173679f160c4cef2db05288548c21e7164170552adae8b13cefaab", 339 | "sha256:5f590fdc84b496e5a4bb5ef99836b0aa688a07cfcb4bc3bb7290f66486f27424" 340 | ], 341 | "index": "pypi", 342 | "version": "==2.5.0" 343 | }, 344 | "service-identity": { 345 | "hashes": [ 346 | "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34", 347 | "sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db" 348 | ], 349 | "version": "==21.1.0" 350 | }, 351 | "six": { 352 | "hashes": [ 353 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 354 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 355 | ], 356 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 357 | "version": "==1.16.0" 358 | }, 359 | "twisted": { 360 | "extras": [ 361 | "http2" 362 | ], 363 | "hashes": [ 364 | "sha256:77544a8945cf69b98d2946689bbe0c75de7d145cdf11f391dd487eae8fc95a12", 365 | "sha256:aab38085ea6cda5b378b519a0ec99986874921ee8881318626b0a3414bb2631e" 366 | ], 367 | "markers": "python_full_version >= '3.5.4'", 368 | "version": "==21.2.0" 369 | }, 370 | "w3lib": { 371 | "hashes": [ 372 | "sha256:0161d55537063e00d95a241663ede3395c4c6d7b777972ba2fd58bbab2001e53", 373 | "sha256:0ad6d0203157d61149fd45aaed2e24f53902989c32fc1dccc2e2bfba371560df" 374 | ], 375 | "version": "==1.22.0" 376 | }, 377 | "zope.interface": { 378 | "hashes": [ 379 | "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192", 380 | "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702", 381 | "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09", 382 | "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4", 383 | "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a", 384 | "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3", 385 | "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf", 386 | "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c", 387 | "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d", 388 | "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78", 389 | "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83", 390 | "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531", 391 | "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46", 392 | "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021", 393 | "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94", 394 | "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc", 395 | "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63", 396 | "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54", 397 | "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117", 398 | "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25", 399 | "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05", 400 | "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e", 401 | "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1", 402 | "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004", 403 | "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2", 404 | "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e", 405 | "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f", 406 | "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f", 407 | "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120", 408 | "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f", 409 | "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1", 410 | "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9", 411 | "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e", 412 | "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7", 413 | "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8", 414 | "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b", 415 | "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155", 416 | "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7", 417 | "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c", 418 | "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325", 419 | "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d", 420 | "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb", 421 | "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e", 422 | "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959", 423 | "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7", 424 | "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920", 425 | "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e", 426 | "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48", 427 | "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8", 428 | "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4", 429 | "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263" 430 | ], 431 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 432 | "version": "==5.4.0" 433 | } 434 | }, 435 | "develop": {} 436 | } 437 | --------------------------------------------------------------------------------