PK!eb% CHANGELOG* Version 1.0.0 + Data :: <2019-02-28 Thu> + Changes :: Now, old HTTP methods (~get~ and ~post~) cannot accept multiple URLs. Instead, we can use ~gets~ and ~posts~. + Adds :: - ~nacf.html~ - ~nacf.json~ - ~nacf.gets~ - ~nacf.posts~ + Includes :: - ~nalude~ * Version 0.1.2 + Data :: <2018-12-26 Wed> + Fixed :: ~inspect.Parameter~ error in last version. * Version 0.1.1 + Data :: <2018-12-26 Wed> + Ignored :: An error caused by ~inspect.Parameter~ + Help Wanted :: Can someone help me about the Parameter? * Version 0.1.0 + Date :: <2018-12-23 Sun> + Commemorate Version :: First Version - Basic Functions. PK!Ђ,, README.org#+OPTIONS: ':t *:t -:t ::t <:t H:5 \n:nil ^:{} arch:headline author:t #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t #+OPTIONS: email:nil f:t inline:t num:nil p:t pri:nil prop:nil stat:t tags:t #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:t todo:t |:t #+TITLE: README #+DATE: <2018-12-23 Sun> #+AUTHOR: Nasy #+EMAIL: nasyxx@gmail.com #+LANGUAGE: en #+SELECT_TAGS: export #+EXCLUDE_TAGS: noexport #+CREATOR: Emacs 27.0.50 (Org mode 9.1.9) #+SETUPFILE: https://fniessen.github.io/org-html-themes/setup/theme-readtheorg.setup * Prologue Never had such a pure crawler like this ~nacf~. Although I often write crawlers, I don't like to use huge frameworks, such as scrapy, but prefer simple ~requests+bs4~ or more general ~requests_html~. However, these two are inconvenient for a crawler. E.g. Places, such as error retrying or parallel crawling, need to be handwritten by myself. It is not very difficult to write it while writing too much can be tedious. Hence I started writing this nacf (Nasy Crawler Framework), hoping to simplify some error retrying or parallel writing of crawlers. * Packages #+caption: Packages | Package | Version | Description | |---------------+---------+----------------------------------------------------| | requests-html | 0.9.0 | HTML Parsing for Humans. | | nalude | 0.2.0 | A standard module. Inspired by Haskell's Prelude. | * Development Process #+include: "./todo.org" * Epoligue ** History #+include: "./CHANGELOG" PK!c_nacf/__init__.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- r""" Life's pathetic, have fun ("▔□▔)/hi~♡ Nasy. Excited without bugs:: | * * | . . | . | * , | . | | * | |\___/| | ) -( . · | =\ - /= | )===( * | / - \ | |- | | / - \ 0.|.0 | NASY___\__( (__/_____(\=/)__+1s____________ | ______|____) )______|______|______|______|_ | ___|______( (____|______|______|______|____ | ______|____\_|______|______|______|______|_ | ___|______|______|______|______|______|____ | ______|______|______|______|______|______|_ | ___|______|______|______|______|______|____ author : Nasy https://nasy.moe date : Dec 23, 2018 email : Nasy filename : __init__.py project : nacf license : GPL-3.0+ There are more things in heaven and earth, Horatio, than are dreamt. -- From "Hamlet" """ __version__ = "1.0.0" # Local Packages from .models import (css, get, gets, html, json, post, text, urls, posts, xpath, parallel,) if __name__ == "__main__": assert css assert get assert gets assert post assert posts assert html assert json assert text assert urls assert xpath assert parallel PK!un::nacf/models.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Life's pathetic, have fun ("▔□▔)/hi~♡ Nasy. Excited without bugs:: | * * | . . | . | * , | . | | * | |\___/| | ) -( . · | =\ - /= | )===( * | / - \ | |- | | / - \ 0.|.0 | NASY___\__( (__/_____(\=/)__+1s____________ | ______|____) )______|______|______|______|_ | ___|______( (____|______|______|______|____ | ______|____\_|______|______|______|______|_ | ___|______|______|______|______|______|____ | ______|______|______|______|______|______|_ | ___|______|______|______|______|______|____ author : Nasy https://nasy.moe date : Dec 24, 2018 update : Feb 28, 2019 email : Nasy filename : models.py project : nacf license : GPL-3.0+ There are more things in heaven and earth, Horatio, than are dreamt. -- From "Hamlet" """ # Standard Library from inspect import Parameter from functools import wraps from itertools import chain, cycle from multiprocessing.dummy import Pool # Web Packages from requests_html import HTMLSession as s # Local Packages from .tools import format_url, generate_sig from .types import (RT, HTML, Ele, Res, Url, Data, Eles, Func, Json, List, Urls, EFunc, Reses, RFunc, SFunc, Tuple, Union, RsFunc, Callable, Iterable, Optional, a, b,) def urls(urls_: Urls, **kwds: a) -> Callable[[Func], Func]: """Feed urls to next function.""" def decorator(func: Func) -> Func: """Decorate function func.""" @wraps(func) def wrapper() -> RT: """Wrap function func.""" return func(_urls=urls_, **kwds) return wrapper return decorator def parallel(n: Optional[int] = None, **kwds: a) -> Callable[[Func], Func]: """Run parallelly.""" def decorator(func: Func) -> Func: """Decorate function func.""" @wraps(func) def wrapper( _urls: Urls, *, _datas: Optional[Iterable[Data]] = None, _jsons: Optional[Iterable[Json]] = None, **_kwds: b, ) -> RT: """Wrap function func.""" def runner(udj: Tuple[Url, Optional[Data], Optional[Json]]) -> RT: """Run func wrapper.""" url, data, json = udj return ( func(url, _data=data, _json=json, **_kwds, **kwds) if data or json else func(url, **_kwds, **kwds) ) with Pool(n) as pool: res = pool.map( runner, zip( _urls, _datas or cycle([None]), _jsons or cycle([dict()]), ), ) return res setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_datas", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[Iterable[Data]]", ), Parameter( "_jsons", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[Iterable[Json]]", ), ), ) return wrapper return decorator def get(url: Url = None, **kwds: a) -> Callable[[RFunc], RFunc]: """Get url.""" def decorator(func: RFunc) -> RFunc: """Decorate function func.""" @wraps(func) def wrapper( _url: Optional[Url] = None, *, _s: Optional[s] = None ) -> Res: """Wrap function func.""" return func((_s or s()).get(format_url(_url or url), **kwds)) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_url", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Url]", ), Parameter( "_s", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[HTMLSession]", ), ), ) return wrapper return decorator def gets(urls: Urls = None, **kwds: a) -> Callable[[RsFunc], RsFunc]: """Get url.""" def decorator(func: RsFunc) -> RsFunc: """Decorate function func.""" @wraps(func) def wrapper( _urls: Optional[Urls] = None, *, _s: Optional[s] = None ) -> Reses: """Wrap function func.""" return func( map( lambda u: (_s or s()).get(format_url(u)), _urls or urls or [""], ), **kwds, ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_urls", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Urls]", ), Parameter( "_s", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[HTMLSession]", ), ), ) return wrapper return decorator def post( url: Optional[Url] = None, *, data: Data = None, json: Json = None, **kwds: a, ) -> Callable[[RFunc], RFunc]: """Post url with data and json.""" def decorator(func: RFunc) -> RFunc: """Decorate function func.""" @wraps(func) def wrapper( _url: Optional[Url] = None, _data: Optional[Data] = None, _json: Optional[Json] = None, *, _s: Optional[s] = None, ) -> Res: """Wrap function func.""" return func( (_s or s()).post(format_url(url), data=data, json=json, **kwds) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_url", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Url]", ), Parameter( "_data", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Data]", ), Parameter( "_json", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Json]", ), Parameter( "_s", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[HTMLSession]", ), ), ) return wrapper return decorator def posts( urls: Optional[Urls] = None, *, datas: Optional[Iterable[Data]] = None, jsons: Optional[Iterable[Json]] = None, **kwds: a, ) -> Callable[[RsFunc], RsFunc]: """Post url with data and json.""" def decorator(func: RsFunc) -> RsFunc: """Decorate function func.""" @wraps(func) def wrapper( _urls: Optional[Urls] = None, *, _datas: Optional[Iterable[Data]] = None, _jsons: Optional[Iterable[Json]] = None, _s: Optional[s] = None, ) -> Res: """Wrap function func.""" def _post(udj: Tuple[Url, Data, Json]) -> Res: """Make a post.""" url, data, json = udj return (_s or s()).post( format_url(url), data=data, json=json, **kwds ) return func( map( _post, zip( _urls or urls or [""], _datas or datas or cycle([None]), _jsons or jsons or cycle([dict()]), ), ) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_urls", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Urls]", ), Parameter( "_datas", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Iterable[Data]]", ), Parameter( "_jsons", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Optional[Iterable[Json]]", ), Parameter( "_s", Parameter.KEYWORD_ONLY, default=None, annotation="Optional[HTMLSession]", ), ), ) return wrapper return decorator def css( selector: str = "*", *, containing: Union[str, List[str]] = None, clean: bool = False, first: bool = False, _encoding: str = None, ) -> Callable[[EFunc], EFunc]: """Css response.""" def decorator(func: EFunc) -> EFunc: """Decorate function func.""" @wraps(func) def wrapper(_res: Union[Res, Reses]) -> Union[Ele, Eles]: """Wrap function func.""" return ( func( _res.html.find( selector, containing=containing, clean=clean, first=first, _encoding=_encoding, ) ) if isinstance(_res, Res) else func( (lambda ele: ele if first else chain.from_iterable(ele))( map( lambda r: r.html.find( selector, containing=containing, clean=clean, first=first, _encoding=_encoding, ), _res, ) ) ) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_res", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Res", ), ), ) return wrapper return decorator def xpath( selector: str, *, clean: bool = False, first: bool = False, _encoding: str = None, ) -> Callable[[EFunc], EFunc]: """Css response.""" def decorator(func: EFunc) -> EFunc: """Decorate function func.""" @wraps(func) def wrapper(_res: Union[Res, Reses]) -> Union[Ele, Eles]: """Wrap function func.""" return func( _res.html.xpath( selector, clean=clean, first=first, _encoding=_encoding ) if isinstance(_res, Res) else (lambda ele: ele if first else chain.from_iterable(ele))( map( lambda r: r.html.xpath( selector, clean=clean, first=first, _encoding=_encoding, ), _res, ) ) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_res", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Res", ), ), ) return wrapper return decorator def html(func: SFunc) -> SFunc: """Get html from response.""" @wraps(func) def wrapper(_res: Union[Res, Reses]) -> Union[HTML, Iterable[HTML]]: """Wrap function func.""" return ( func(_res.html) if isinstance(_res, Res) else map(lambda r: r.html, _res) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_res", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Res", ), ), ) return wrapper def json( func: Callable[..., Union[Json, Iterable[Json]]] ) -> Callable[[Union[Res, Reses]], Union[Json, Iterable[Json]]]: """Get json from response.""" @wraps(func) def wrapper(_res: Union[Res, Reses]) -> Union[Json, Iterable[Json]]: """Wrap function func.""" return ( func(_res.json()) if isinstance(_res, Res) else map(lambda r: r.json(), _res) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_res", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Res", ), ), ) return wrapper def text(func: SFunc) -> SFunc: """Get text from response or element(s) from css/xpath.""" @wraps(func) def wrapper(_ele: Union[Res, Ele, Eles]) -> Union[str, Iterable[str]]: """Wrap function func.""" return func( _ele.text if isinstance(_ele, Ele) or isinstance(_ele, Res) else map(lambda e: e.text, _ele) ) setattr( wrapper, "__signature__", generate_sig( func, Parameter( "_ele", Parameter.POSITIONAL_OR_KEYWORD, default=None, annotation="Union[Res, Ele, Eles]", ), ), ) return wrapper PK!h  nacf/tools.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Life's pathetic, have fun ("▔□▔)/hi~♡ Nasy. Excited without bugs:: | * * | . . | . | * , | . | | * | |\___/| | ) -( . · | =\ - /= | )===( * | / - \ | |- | | / - \ 0.|.0 | NASY___\__( (__/_____(\=/)__+1s____________ | ______|____) )______|______|______|______|_ | ___|______( (____|______|______|______|____ | ______|____\_|______|______|______|______|_ | ___|______|______|______|______|______|____ | ______|______|______|______|______|______|_ | ___|______|______|______|______|______|____ author : Nasy https://nasy.moe date : Dec 23, 2018 email : Nasy filename : tools.py project : nacf license : GPL-3.0+ There are more things in heaven and earth, Horatio, than are dreamt. -- From "Hamlet" """ # Standard Library from inspect import Parameter, Signature, signature # Prelude from nalude import flatten # Local Packages from .types import Url, Func, Optional def format_url(url: Optional[Url]) -> Optional[Url]: """Add schema to url.""" return ( url if url and url.startswith("http") else url and ("https://" + url) ) def generate_sig(func: Func, *params: Parameter) -> Signature: """Generate signature with param from func.""" return signature(func).replace( parameters=list(signature(func).parameters.values()) + list(params) ) __all__ = ["format_url", "flatten"] PK!V nacf/types.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Life's pathetic, have fun ("▔□▔)/hi~♡ Nasy. Excited without bugs:: | * * | . . | . | * , | . | | * | |\___/| | ) -( . · | =\ - /= | )===( * | / - \ | |- | | / - \ 0.|.0 | NASY___\__( (__/_____(\=/)__+1s____________ | ______|____) )______|______|______|______|_ | ___|______( (____|______|______|______|____ | ______|____\_|______|______|______|______|_ | ___|______|______|______|______|______|____ | ______|______|______|______|______|______|_ | ___|______|______|______|______|______|____ author : Nasy https://nasy.moe date : Dec 23, 2018 email : Nasy filename : types.py project : nacf license : GPL-3.0+ There are more things in heaven and earth, Horatio, than are dreamt. -- From "Hamlet" """ # Standard Library from typing import (IO, Dict, List, Tuple, Union, TypeVar, Callable, Iterable, Optional, ByteString,) # Web Packages from requests_html import HTML from requests_html import Element as Ele from requests_html import HTMLResponse as Res # Normal a = TypeVar("a") b = TypeVar("b") # function RT = TypeVar("RT") Func = Callable[..., RT] Reses = Iterable[Res] RFunc = Callable[..., Res] RsFunc = Callable[..., Reses] Eles = Iterable[Ele] EFunc = Callable[..., Union[Ele, Eles]] SFunc = Callable[..., Union[str, Iterable[str]]] # request Data = Optional[Union[Dict[str, a], ByteString, IO]] Json = Dict[str, a] Url = str Urls = Iterable[Url] __all__ = [ "Res", "Reses", "HTML", "a", "b", "RT", "Func", "RFunc", "RsFunc", "SFunc", "Data", "Json", "Url", "Urls", "List", "Tuple", ] PK!+n0;0; poetry.lock[[package]] category = "main" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" optional = false python-versions = "*" version = "1.4.3" [[package]] category = "dev" description = "Atomic file writes." name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.3.0" [[package]] category = "dev" description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = "*" version = "18.2.0" [package.extras] dev = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface", "sphinx", "zope.interface", "pre-commit"] docs = ["sphinx", "zope.interface"] tests = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface"] [[package]] category = "main" description = "Screen-scraping library" name = "beautifulsoup4" optional = false python-versions = "*" version = "4.7.1" [package.dependencies] soupsieve = ">=1.2" [package.extras] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] category = "main" description = "Dummy package for Beautiful Soup" name = "bs4" optional = false python-versions = "*" version = "0.0.1" [package.dependencies] beautifulsoup4 = "*" [[package]] category = "main" description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" version = "2018.11.29" [[package]] category = "main" description = "Universal encoding detector for Python 2 and 3" name = "chardet" optional = false python-versions = "*" version = "3.0.4" [[package]] category = "dev" description = "Cross-platform colored terminal text." marker = "sys_platform == \"win32\"" name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "0.4.1" [[package]] category = "main" description = "cssselect parses CSS3 Selectors and translates them to XPath 1.0" name = "cssselect" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.0.3" [[package]] category = "main" description = "Up to date simple useragent faker with real world database" name = "fake-useragent" optional = false python-versions = "*" version = "0.1.11" [[package]] category = "dev" description = "A library for property based testing" name = "hypothesis" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "3.88.3" [package.dependencies] attrs = ">=16.0.0" [package.extras] all = ["Faker (>=0.7)", "Faker (>=0.7)", "django (>=1.11)", "dpcontracts (>=0.4)", "numpy (>=1.9.0)", "pandas (>=0.19)", "pytest (>=3.0)", "python-dateutil (>=1.4)", "pytz", "pytz (>=2014.1)", "pytz (>=2014.1)"] datetime = ["pytz (>=2014.1)"] dateutil = ["python-dateutil (>=1.4)"] django = ["pytz", "django (>=1.11)"] dpcontracts = ["dpcontracts (>=0.4)"] fakefactory = ["Faker (>=0.7)"] faker = ["Faker (>=0.7)"] numpy = ["numpy (>=1.9.0)"] pandas = ["pandas (>=0.19)"] pytest = ["pytest (>=3.0)"] pytz = ["pytz (>=2014.1)"] [[package]] category = "main" description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.8" [[package]] category = "main" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." name = "lxml" optional = false python-versions = "*" version = "4.3.1" [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.1)"] [[package]] category = "dev" description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" optional = false python-versions = ">=3.4" version = "6.0.0" [[package]] category = "main" description = "A standard module. Inspired by Haskell's Prelude." name = "nalude" optional = false python-versions = ">=3.6,<4.0" version = "0.2.0" [[package]] category = "main" description = "parse() is the opposite of format()" name = "parse" optional = false python-versions = "*" version = "1.11.1" [[package]] category = "dev" description = "plugin and hook calling mechanisms for python" name = "pluggy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "0.9.0" [package.extras] dev = ["pre-commit", "tox"] [[package]] category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.8.0" [[package]] category = "main" description = "A port of node.js's EventEmitter to python." name = "pyee" optional = false python-versions = "*" version = "5.0.0" [[package]] category = "main" description = "Headless chrome/chromium automation library (unofficial port of puppeteer)" name = "pyppeteer" optional = false python-versions = ">=3.5" version = "0.0.25" [package.dependencies] appdirs = "*" pyee = "*" tqdm = "*" urllib3 = "*" websockets = "*" [[package]] category = "main" description = "A jquery-like library for python" name = "pyquery" optional = false python-versions = "*" version = "1.4.0" [package.dependencies] cssselect = ">0.7.9" lxml = ">=2.1" [[package]] category = "dev" description = "pytest: simple powerful testing with Python" name = "pytest" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "3.10.1" [package.dependencies] atomicwrites = ">=1.0" attrs = ">=17.4.0" colorama = "*" more-itertools = ">=4.0.0" pluggy = ">=0.7" py = ">=1.5.0" setuptools = "*" six = ">=1.10.0" [[package]] category = "main" description = "Python HTTP for Humans." name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.21.0" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<3.1.0" idna = ">=2.5,<2.9" urllib3 = ">=1.21.1,<1.25" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] category = "main" description = "HTML Parsing for Humans." name = "requests-html" optional = false python-versions = ">=3.6.0" version = "0.9.0" [package.dependencies] bs4 = "*" fake-useragent = "*" parse = "*" pyppeteer = ">=0.0.14" pyquery = "*" requests = "*" w3lib = "*" [[package]] category = "main" description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" version = "1.12.0" [[package]] category = "main" description = "A CSS4 selector implementation for Beautiful Soup." name = "soupsieve" optional = false python-versions = "*" version = "1.8" [[package]] category = "main" description = "Fast, Extensible Progress Meter" name = "tqdm" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" version = "4.31.1" [package.extras] dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown"] [[package]] category = "main" description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" version = "1.24.1" [package.extras] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] category = "main" description = "Library of web-related functions" name = "w3lib" optional = false python-versions = "*" version = "1.20.0" [package.dependencies] six = ">=1.4.1" [[package]] category = "main" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" name = "websockets" optional = false python-versions = ">=3.4" version = "7.0" [metadata] content-hash = "0846f0d679bb4f93802c29cd336dec8b313a3460f0b5a7fcee8ec2510faa671d" python-versions = "^3.7" [metadata.hashes] appdirs = ["9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"] atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] attrs = ["10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", "ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"] beautifulsoup4 = ["034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858", "945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348", "ba6d5c59906a85ac23dadfe5c88deaf3e179ef565f4898671253e50a78680718"] bs4 = ["36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"] certifi = ["47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", "993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"] chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] cssselect = ["066d8bc5229af09617e24b3ca4d52f1f9092d9e061931f4184cd572885c23204", "3b5103e8789da9e936a68d993b70df732d06b8bb9a337a05ed4eb52c17ef7206"] fake-useragent = ["c104998b750eb097eefc28ae28e92d66397598d2cf41a31aa45d5559ef1adf35"] hypothesis = ["21000d6c13bc7ad360f416eade493a06f2632c9c2a732e493779f8d51c08f031", "3b1aa7d49bc5f69948425d4a55b5edf4c75d79cbac72b47ab3061f55ad727b74", "76bfc9838d0b589fbc25232f46ec8ae17504f013b25d8221aa03d5368413016c"] idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] lxml = ["0537eee4902e8bf4f41bfee8133f7edf96533dd175930a12086d6a40d62376b2", "0562ec748abd230ab87d73384e08fa784f9b9cee89e28696087d2d22c052cc27", "09e91831e749fbf0f24608694e4573be0ef51430229450c39c83176cc2e2d353", "1ae4c0722fc70c0d4fba43ae33c2885f705e96dce1db41f75ae14a2d2749b428", "1c630c083d782cbaf1f7f37f6cac87bda9cff643cf2803a5f180f30d97955cef", "2fe74e3836bd8c0fa7467ffae05545233c7f37de1eb765cacfda15ad20c6574a", "37af783c2667ead34a811037bda56a0b142ac8438f7ed29ae93f82ddb812fbd6", "3f2d9eafbb0b24a33f56acd16f39fc935756524dcb3172892721c54713964c70", "47d8365a8ef14097aa4c65730689be51851b4ade677285a3b2daa03b37893e26", "510e904079bc56ea784677348e151e1156040dbfb736f1d8ea4b9e6d0ab2d9f4", "58d0851da422bba31c7f652a7e9335313cf94a641aa6d73b8f3c67602f75b593", "7940d5c2185ffb989203dacbb28e6ae88b4f1bb25d04e17f94b0edd82232bcbd", "7cf39bb3a905579836f7a8f3a45320d9eb22f16ab0c1e112efb940ced4d057a5", "9563a23c1456c0ab550c087833bc13fcc61013a66c6420921d5b70550ea312bf", "95b392952935947e0786a90b75cc33388549dcb19af716b525dae65b186138fc", "983129f3fd3cef5c3cf067adcca56e30a169656c00fcc6c648629dbb850b27fa", "a0b75b1f1854771844c647c464533def3e0a899dd094a85d1d4ed72ecaaee93d", "b5db89cc0ef624f3a81214b7961a99f443b8c91e88188376b6b322fd10d5b118", "c0a7751ba1a4bfbe7831920d98cee3ce748007eab8dfda74593d44079568219a", "c0c5a7d4aafcc30c9b6d8613a362567e32e5f5b708dc41bc3a81dac56f8af8bb", "d4d63d85eacc6cb37b459b16061e1f100d154bee89dc8d8f9a6128a5a538e92e", "da5e7e941d6e71c9c9a717c93725cda0708c2474f532e3680ac5e39ec57d224d", "dccad2b3c583f036f43f80ac99ee212c2fa9a45151358d55f13004d095e683b2", "df46307d39f2aeaafa1d25309b8a8d11738b73e9861f72d4d0a092528f498baa", "e70b5e1cb48828ddd2818f99b1662cb9226dc6f57d07fc75485405c77da17436", "ea825562b8cd057cbc9810d496b8b5dec37a1e2fc7b27bc7c1e72ce94462a09a"] more-itertools = ["0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40", "590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1"] nalude = ["7b6afe42a5698e9a2fc8b7ca3f4ccd7ef4b5a9f7dcc439d1e1c9e8b7e7a6acaf", "d885d9dbbd9e1248ebe709704aa36bc01982151cdc01437ded90dd4830d4535f"] parse = ["870dd675c1ee8951db3e29b81ebe44fd131e3eb8c03a79483a58ea574f3145c2"] pluggy = ["19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f", "84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"] py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] pyee = ["47f8fa96d6dee61c82001831e1fbba55f3f808003a322d0e6653aa01c59f6b9e", "4ec22817297b7024f89721cc34f790ee2767c5b5ca44284c565ee643abafbe32"] pyppeteer = ["51fe769b722a1718043b74d12c20420f29e0dd9eeea2b66652b7f93a9ad465dd"] pyquery = ["07987c2ed2aed5cba29ff18af95e56e9eb04a2249f42ce47bddfb37f487229a3", "4771db76bd14352eba006463656aef990a0147a0eeaf094725097acfa90442bf"] pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"] requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] requests-html = ["34257d5249b20b8ed14573eba910f48032a61205e70d11ce8a3ef6abf8edc50b", "9686f21c5753ba6c025c6ba223a8329c7b149a935a73055097faf8999eee85b1"] six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] soupsieve = ["afa56bf14907bb09403e5d15fbed6275caa4174d36b975226e3b67a3bb6e2c4b", "eaed742b48b1f3e2d45ba6f79401b2ed5dc33b2123dfe216adb90d4bfa0ade26"] tqdm = ["d385c95361699e5cf7622485d9b9eae2d4864b21cd5a2374a9c381ffed701021", "e22977e3ebe961f72362f6ddfb9197cc531c9737aaf5f607ef09740c849ecd05"] urllib3 = ["61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"] w3lib = ["67eacd24f4f233a80bc472835ad6aad99616e49aa1d795f3dbb7b8b028fec6cf", "e54db912ae1c79d3e246b16d3645bdf701f70ac4f8a2fc46eeb284cc02a31cd7"] websockets = ["04b42a1b57096ffa5627d6a78ea1ff7fad3bc2c0331ffc17bc32a4024da7fea0", "08e3c3e0535befa4f0c4443824496c03ecc25062debbcf895874f8a0b4c97c9f", "10d89d4326045bf5e15e83e9867c85d686b612822e4d8f149cf4840aab5f46e0", "232fac8a1978fc1dead4b1c2fa27c7756750fb393eb4ac52f6bc87ba7242b2fa", "4bf4c8097440eff22bc78ec76fe2a865a6e658b6977a504679aaf08f02c121da", "51642ea3a00772d1e48fb0c492f0d3ae3b6474f34d20eca005a83f8c9c06c561", "55d86102282a636e195dad68aaaf85b81d0bef449d7e2ef2ff79ac450bb25d53", "564d2675682bd497b59907d2205031acbf7d3fadf8c763b689b9ede20300b215", "5d13bf5197a92149dc0badcc2b699267ff65a867029f465accfca8abab95f412", "5eda665f6789edb9b57b57a159b9c55482cbe5b046d7db458948370554b16439", "5edb2524d4032be4564c65dc4f9d01e79fe8fad5f966e5b552f4e5164fef0885", "79691794288bc51e2a3b8de2bc0272ca8355d0b8503077ea57c0716e840ebaef", "7fcc8681e9981b9b511cdee7c580d5b005f3bb86b65bde2188e04a29f1d63317", "8e447e05ec88b1b408a4c9cde85aa6f4b04f06aa874b9f0b8e8319faf51b1fee", "90ea6b3e7787620bb295a4ae050d2811c807d65b1486749414f78cfd6fb61489", "9e13239952694b8b831088431d15f771beace10edfcf9ef230cefea14f18508f", "d40f081187f7b54d7a99d8a5c782eaa4edc335a057aa54c85059272ed826dc09", "e1df1a58ed2468c7b7ce9a2f9752a32ad08eac2bcd56318625c3647c2cd2da6f", "e98d0cec437097f09c7834a11c69d79fe6241729b23f656cfc227e93294fc242", "f8d59627702d2ff27cb495ca1abdea8bd8d581de425c56e93bff6517134e0a9b", "fc30cdf2e949a2225b012a7911d1d031df3d23e99b7eda7dfc982dc4a860dae9"] PK!Hu)GTUnacf-1.0.0.dist-info/WHEEL HM K-*ϳR03rOK-J,/R(O-)$qzd&Y)r$UV&UrPK!HؤInacf-1.0.0.dist-info/METADATAW[o6~ׯ8"imY8voY.M, t0 3-Q2IH*ΑhKWذ>4ya3WZ|;,CY;ͺzܖYbL/Dy+TKu\\t΀AQ*a-:2㝂%`fLn"̬̺9[!5ʽ\_H̤ñ1Rd .%r|BqݹY05>h;I" Z0K8. %xD?;sR)`ݯcL*HrVlQ2g"OIU%ujnCNn)n*֯T1% g񲂄~G#RaPqu"B:8쌏<7psw~rm3=\|p5ZρPr`E(4"#9cӔi:IF {^kXxU^ٽҢk+׏JA%zIyjF70fv?~[ߗ5~#s.>ˁ+p@7P@΂aofb<(<*k}Y|vhsWypξp?j,n-<|[۳B9庠*-;h˶ "ݠ [A~\uA/߈Z+ƣ.FXt2 j8)N2%b s%L۸$ ì7m]jb64P("+&ˆ~3{|;'>q.2jХK$P<E1a8snRƭF-h0&.![ SLJ2]8B4F|4a- q,25VNL>ɗjL Yjʎ!KGpuAGD';O8pVơ}$4lyZd(dhQȪ !)r Z%N^fSZzQdƍQC_Pe1~FIylZVfcCdUA+!_U} LeZ(zjcuEiϊ׮ѭTF&豉etSP1z$g#n'jCw?^` j2cvJB Mr?pDeʩnAa+ȵa@[ȳFYfAsY,-e.&[Y◃Yed6r $n%Ĕ\WȔ;OZs֊*sWT?70DE} S@Q"P]t(ülQڼ™\^Jiy]57ʮ`|ը 1 }ќ?A4T!%LVnR&פmN$;,>$dں ˮ>3@R@zʮg^ՠP܆Q8`] x_-8V7UʞPK!eb% CHANGELOGPK!Ђ,, README.orgPK!c_nacf/__init__.pyPK!un:: nacf/models.pyPK!h  Inacf/tools.pyPK!V Pnacf/types.pyPK!+n0;0; Ypoetry.lockPK!Hu)GTU_nacf-1.0.0.dist-info/WHEELPK!HؤInacf-1.0.0.dist-info/METADATAPK!H(nacf-1.0.0.dist-info/RECORDPK t4