import re import logging import threading import time from flask import Flask, jsonify, request import netrc import json from json.decoder import JSONDecodeError from platform import uname from sys import platform from urllib.request import urlopen import asyncio from queue import Queue from threading import Thread from habanero import Crossref from waitress import serve if platform in ("linux", "linux2"): SEPARATOR_FILE_PATH = "/" if "microsoft-standard" in uname().release: NETRC_FILE = "/home/mtuszowski/.netrc" else: NETRC_FILE = "/home/pi/.netrc" elif platform == "win32": NETRC_FILE = "C:\\Users\\mtusz\\.netrc" #HOST_ADDRESS = "192.168.1.191" HOST_ADDRESS = "0.0.0.0" PORT_ADDRESS = 5001 DATABASE_PATH = r'C:\\Database\\chunks' ENCODING = "utf-8" class Librarian(object): def __init__(self) -> None: netrc_mod = netrc.netrc(NETRC_FILE) authTokens = netrc_mod.authenticators("crossref") self.cr = Crossref(mailto=authTokens[0]) self.limit = 1000 self.fetched = 0 self.hit = 0 self.total = 0 def search_crossref(self, query, uuid): search_result_from_cr = self.cr.works(query = query, limit = self.limit) self.total = search_result_from_cr['message']['total-results'] self.fetched = len(search_result_from_cr['message']['items']) #add to sql with UUID #sql row - title, doi, author, uuid, last retrieved, is_available with open("results.json", "r+", encoding="UTF-8") as data_file: # First we load existing data into a dict. try: file_data = json.load(data_file) except JSONDecodeError: file_data = [] # Join new_data with file_data inside emp_details summarized_results = [] for item in search_result_from_cr['message']['items']: container = "NO" if "container-title" in item: container = "YES" summarized_results.append({"DOI" : item['DOI'], "title": item['title'] if 'title' in item else None,"type": item['type'] if 'type' in item else None, "container": container}) result = {"UUID": uuid, "total_results": search_result_from_cr['message']['total-results'], "on_page" : 1, "summary":summarized_results, "results":search_result_from_cr['message']['items'], } file_data.append(result) print("Saving") data_file.seek(0) # convert back to json. json.dump(file_data, data_file, indent=4) return result #TODO: check if exists odpala wątki dla kolejnych plików, z każdego wątku dostaje zwrotki - trafienia na bieżąco oraz sygnał że plik się skończył i pora na następny #TODO: paczki danych są upychane po 10 w tablicy, POSTy ze strony klienta mówią tylko nazwę tablicy (poprzez UUID) oraz którą stronę tejże #TODO: jeśli UUID nie istnieje to budujemy całość dla nowego uuid #TODO: kiedy wszystkie wątki pilokowe się zakończą - zamykamy merger i dajemy znać do procedury obsługi odpowiadania na posty że dla tego uuid już nic więcej nie znajdziemy #TODO: po 60 minutach storeujemy wyniki zapytania pod query w sql i kasujemy UUID #TODO: Później robimy tak że query jest najpierw sprawdzane w sql - i dawane jako "zapisana lokalna kopia" #TODO: Paginacja - najpierw hity z pliku, potem na końcu to co nie zwróciło żadnych hitów - i to dopiero można crawlerem sprawdzić def check_dois_in_file(self, file_name, dois, out_queue): with open(f'{DATABASE_PATH}{file_name}', "r+", encoding=ENCODING) as file: while True: # Get next line from file line = file.readline() if line == dois: return True # if line is empty # end of file is reached if not line: return False def check_dois_in_local_db(self, dois): _sentinel = object() chunk_list = [] q = Queue() for file in chunk_list: t = Thread(target = self.check_dois_in_file, args = (file ,dois, q)) t.start() q.put(_sentinel) def check_if_exists(self, page_url): if not page_url.startswith(("http:", "https:")): raise ValueError("URL must start with 'http:' or 'https:'") # trunk-ignore(bandit/B310) with urlopen(page_url) as response: data = response.read() text = data.decode("utf-8") for line in text.splitlines(): if re.match(r".*Unfortunately, Sci-Hub doesn't have the requested document.*", line): return None if m := re.match(r".*