Exemplo n.º 1
0
    def fetch(self, request: ScraperRequest) -> Optional[str]:

        centre = _parse_centre(request.get_url())

        # Doctolib fetches multiple vaccination centers sometimes
        # so if a practice id is present in query, only related agendas
        # should be selected.
        practice_id = _parse_practice_id(request.get_url())

        practice_same_adress = False

        rdata = None
        # We already have rdata
        if request.input_data:
            rdata = request.input_data
        else:
            centre_api_url = DOCTOLIB_API.get("booking",
                                              "").format(centre=centre)
            request.increase_request_count("booking")
            response = self._client.get(centre_api_url,
                                        headers=DOCTOLIB_HEADERS)
            if response.status_code == 403:
                raise BlockedByDoctolibError(centre_api_url)

            response.raise_for_status()
            time.sleep(self._cooldown_interval)
            data = response.json()
            rdata = data.get("data", {})

        if not self.is_practice_id_valid(request, rdata):
            logger.warning(
                f"Invalid practice ID for this Doctolib center: {request.get_url()}"
            )
            practice_id = None
            self.pop_practice_id(request)
        if practice_id:
            practice_id, practice_same_adress = link_practice_ids(
                practice_id, rdata)
        if len(rdata.get("places", [])) > 1 and practice_id is None:
            practice_id = rdata.get("places")[0].get("practice_ids", None)

        request.update_practitioner_type(parse_practitioner_type(
            centre, rdata))
        set_doctolib_center_internal_id(request, rdata, practice_id,
                                        practice_same_adress)
        # Check if  appointments are allowed
        if not is_allowing_online_appointments(rdata):
            request.set_appointments_only_by_phone(True)
            return None

        # visit_motive_categories
        # example: https://partners.doctolib.fr/hopital-public/tarbes/centre-de-vaccination-tarbes-ayguerote?speciality_id=5494&enable_cookies_consent=1
        visit_motive_category_id = _find_visit_motive_category_id(rdata)
        # visit_motive_id
        visit_motive_ids = _find_visit_motive_id(
            rdata, visit_motive_category_id=visit_motive_category_id)
        if visit_motive_ids is None:
            return None

        all_agendas = parse_agenda_ids(rdata)
        first_availability = None

        appointment_schedules = request.get_appointment_schedules()

        start_date = request.get_start_date()

        for interval in INTERVAL_SPLIT_DAYS:
            chronodose = False
            if interval == CHRONODOSES["Interval"]:
                chronodose = True

            appointment_schedules = build_appointment_schedules(
                request,
                interval,
                append_date_days(start_date, 0),
                append_date_days(start_date, days=interval, seconds=-1),
                0,
                appointment_schedules,
                chronodose,
            )
        request.update_appointment_schedules(appointment_schedules)

        timetable_start_date = datetime.now()  # shouldn't be datetime.now()!!
        for visit_motive_id in visit_motive_ids:
            agenda_ids, practice_ids = _find_agenda_and_practice_ids(
                rdata, visit_motive_id, practice_id_filter=practice_id)
            if not agenda_ids or not practice_ids:
                continue
            agenda_ids = self.sort_agenda_ids(all_agendas, agenda_ids)

            agenda_ids_q = "-".join(agenda_ids)
            practice_ids_q = "-".join(practice_ids)
            availability = self.get_timetables(
                request,
                visit_motive_ids,
                visit_motive_id,
                agenda_ids_q,
                practice_ids_q,
                timetable_start_date,
                appointment_schedules,
            )
            if availability and (not first_availability
                                 or availability < first_availability):
                first_availability = availability
        return first_availability
Exemplo n.º 2
0
    def fetch(self, request: ScraperRequest) -> Optional[str]:

        centre = _parse_centre(request.get_url())

        # Doctolib fetches multiple vaccination centers sometimes
        # so if a practice id is present in query, only related agendas
        # should be selected.
        practice_id = _parse_practice_id(request.get_url())

        practice_same_adress = False

        centre_api_url = f"https://partners.doctolib.fr/booking/{centre}.json"
        response = self._client.get(centre_api_url, headers=DOCTOLIB_HEADERS)
        if response.status_code == 403:
            raise BlockedByDoctolibError(centre_api_url)

        response.raise_for_status()
        time.sleep(self._cooldown_interval)
        data = response.json()
        rdata = data.get("data", {})

        if not self.is_practice_id_valid(request, rdata):
            logger.warning(f"Invalid practice ID for this Doctolib center: {request.get_url()}")
            practice_id = None
            self.pop_practice_id(request)
        if practice_id:
            practice_id, practice_same_adress = link_practice_ids(practice_id, rdata)
        if len(rdata.get("places", [])) > 1 and practice_id is None:
            practice_id = rdata.get("places")[0].get("practice_ids", None)

        request.update_practitioner_type(parse_practitioner_type(centre, rdata))
        set_doctolib_center_internal_id(request, rdata, practice_id, practice_same_adress)
        # Check if  appointments are allowed
        if not is_allowing_online_appointments(rdata):
            request.set_appointments_only_by_phone(True)
            return None

        # visit_motive_categories
        # example: https://partners.doctolib.fr/hopital-public/tarbes/centre-de-vaccination-tarbes-ayguerote?speciality_id=5494&enable_cookies_consent=1
        visit_motive_category_id = _find_visit_motive_category_id(data)
        # visit_motive_id
        visit_motive_ids = _find_visit_motive_id(data, visit_motive_category_id=visit_motive_category_id)
        if visit_motive_ids is None:
            return None

        all_agendas = parse_agenda_ids(rdata)
        first_availability = None

        appointment_schedules = request.get_appointment_schedules()

        start_date = request.get_start_date()

        for interval in INTERVAL_SPLIT_DAYS:
            chronodose = False
            if interval == CHRONODOSES["Interval"]:
                chronodose = True

            appointment_schedules = build_appointment_schedules(
                request,
                interval,
                append_date_days(start_date, 0),
                append_date_days(start_date, interval, 1),
                0,
                appointment_schedules,
                chronodose,
            )
        request.update_appointment_schedules(appointment_schedules)

        for visit_motive_id in visit_motive_ids:
            agenda_ids, practice_ids = _find_agenda_and_practice_ids(
                data, visit_motive_id, practice_id_filter=practice_id
            )
            if agenda_ids != [] and practice_ids != []:
                agenda_ids = self.sort_agenda_ids(all_agendas, agenda_ids)

                agenda_ids_q = "-".join(agenda_ids)
                practice_ids_q = "-".join(practice_ids)

                for i in range(DOCTOLIB_ITERATIONS):
                    start_date_tmp = datetime.now() + timedelta(days=7 * i)
                    start_date_tmp = start_date_tmp.strftime("%Y-%m-%d")
                    sdate, appt, appointment_schedules, stop = self.get_appointments(
                        request,
                        start_date_tmp,
                        visit_motive_ids,
                        visit_motive_id,
                        agenda_ids_q,
                        practice_ids_q,
                        DOCTOLIB_SLOT_LIMIT,
                        start_date,
                        appointment_schedules,
                    )

                    if stop:
                        break
                    if not sdate:
                        continue
                    if not first_availability or sdate < first_availability:
                        first_availability = sdate

                    request.update_appointment_count(request.appointment_count + appt)
                if appointment_schedules:
                    request.update_appointment_schedules(appointment_schedules)

        return first_availability