Skip to main content
Glama
kaman05010

MCP Wikipedia Server

by kaman05010
__init__.py35.2 kB
""" Wikipedia-API is easy to use wrapper for extracting information from Wikipedia. It supports extracting texts, sections, links, categories, translations, etc. from Wikipedia. Documentation provides code snippets for the most common use cases. """ __version__ = (0, 8, 1) from collections import defaultdict from enum import IntEnum import logging import re from typing import Any, Optional, Union from urllib import parse import requests USER_AGENT = ( "Wikipedia-API/" + ".".join(str(s) for s in __version__) + "; https://github.com/martin-majlis/Wikipedia-API/" ) MIN_USER_AGENT_LEN = 5 MAX_LANG_LEN = 5 log = logging.getLogger(__name__) # https://www.mediawiki.org/wiki/API:Main_page PagesDict = dict[str, "WikipediaPage"] class ExtractFormat(IntEnum): """Represents extraction format.""" WIKI = 1 """ Allows recognizing subsections Example: https://goo.gl/PScNVV """ HTML = 2 """ Alows retrieval of HTML tags Example: https://goo.gl/1Jwwpr """ # Plain: https://goo.gl/MAv2qz # Doesn't allow to recognize subsections # PLAIN = 3 class Namespace(IntEnum): """ Represents namespace in Wikipedia You can gen list of possible namespaces here: * https://en.wikipedia.org/wiki/Wikipedia:Namespace * https://en.wikipedia.org/wiki/Wikipedia:Namespace#Programming Currently following namespaces are supported: """ MAIN = 0 TALK = 1 USER = 2 USER_TALK = 3 WIKIPEDIA = 4 WIKIPEDIA_TALK = 5 FILE = 6 FILE_TALK = 7 MEDIAWIKI = 8 MEDIAWIKI_TALK = 9 TEMPLATE = 10 TEMPLATE_TALK = 11 HELP = 12 HELP_TALK = 13 CATEGORY = 14 CATEGORY_TALK = 15 PORTAL = 100 PORTAL_TALK = 101 PROJECT = 102 PROJECT_TALK = 103 REFERENCE = 104 REFERENCE_TALK = 105 BOOK = 108 BOOK_TALK = 109 DRAFT = 118 DRAFT_TALK = 119 EDUCATION_PROGRAM = 446 EDUCATION_PROGRAM_TALK = 447 TIMED_TEXT = 710 TIMED_TEXT_TALK = 711 MODULE = 828 MODULE_TALK = 829 GADGET = 2300 GADGET_TALK = 2301 GADGET_DEFINITION = 2302 GADGET_DEFINITION_TALK = 2303 WikiNamespace = Union[Namespace, int] def namespace2int(namespace: WikiNamespace) -> int: """Converts namespace into integer""" if isinstance(namespace, Namespace): return namespace.value return namespace RE_SECTION = { ExtractFormat.WIKI: re.compile(r"\n\n *(==+) (.*?) (==+) *\n"), ExtractFormat.HTML: re.compile( r"\n? *<h([1-9])[^>]*?>(<span[^>]*></span>)? *" + "(<span[^>]*>)? *(<span[^>]*></span>)? *(.*?) *" + "(</span>)?(<span>Edit</span>)?</h[1-9]>\n?" # ^^^^ # Example page with 'Edit' erroneous links: https://bit.ly/2ui4FWs ), # ExtractFormat.PLAIN.value: re.compile(r'\n\n *(===*) (.*?) (===*) *\n'), } class Wikipedia: """Wikipedia is wrapper for Wikipedia API.""" def __init__( self, user_agent: str, language: str = "en", variant: Optional[str] = None, extract_format: ExtractFormat = ExtractFormat.WIKI, headers: Optional[dict[str, Any]] = None, extra_api_params: Optional[dict[str, Any]] = None, **request_kwargs, ) -> None: """ Constructs Wikipedia object for extracting information Wikipedia. :param user_agent: HTTP User-Agent used in requests https://meta.wikimedia.org/wiki/User-Agent_policy :param language: Language mutation of Wikipedia - http://meta.wikimedia.org/wiki/List_of_Wikipedias :param variant: Language variant. Only works if the base language supports variant conversion. :param extract_format: Format used for extractions :class:`ExtractFormat` object. :param headers: Headers sent as part of HTTP request :param extra_api_params: Extra parameters that are used to construct query string when calling Wikipedia API :param request_kwargs: Optional parameters used in - http://docs.python-requests.org/en/master/api/#requests.request Examples: * Proxy: ``Wikipedia('foo (merlin@example.com)', proxies={'http': 'http://proxy:1234'})`` """ request_kwargs.setdefault("timeout", 10.0) default_headers = {} if headers is None else headers if user_agent is not None: default_headers.setdefault( "User-Agent", user_agent, ) used_language, used_variant, used_user_agent = self._check_and_correct_params( language, variant, default_headers.get("User-Agent"), ) default_headers["User-Agent"] = used_user_agent + " (" + USER_AGENT + ")" self.language = used_language self.variant = used_variant self.extract_format = extract_format log.info( "Wikipedia: language=%s, user_agent: %s, extract_format=%s", self.language, default_headers["User-Agent"], self.extract_format, ) self._extra_api_params = extra_api_params self._session = requests.Session() self._session.headers.update(default_headers) self._request_kwargs = request_kwargs def __del__(self) -> None: """Closes session.""" if hasattr(self, "_session") and self._session: self._session.close() def page( self, title: str, ns: WikiNamespace = Namespace.MAIN, unquote: bool = False, ) -> "WikipediaPage": """ Constructs Wikipedia page with title `title`. Creating `WikipediaPage` object is always the first step for extracting any information. Example:: wiki_wiki = wikipediaapi.Wikipedia('en') page_py = wiki_wiki.page('Python_(programming_language)') print(page_py.title) # Python (programming language) wiki_hi = wikipediaapi.Wikipedia('hi') page_hi_py = wiki_hi.article( title='%E0%A4%AA%E0%A4%BE%E0%A4%87%E0%A4%A5%E0%A4%A8', unquote=True, ) print(page_hi_py.title) # पाइथन :param title: page title as used in Wikipedia URL :param ns: :class:`WikiNamespace` :param unquote: if true it will unquote title :return: object representing :class:`WikipediaPage` """ if unquote: title = parse.unquote(title) return WikipediaPage( self, title=title, ns=ns, language=self.language, variant=self.variant ) def article( self, title: str, ns: WikiNamespace = Namespace.MAIN, unquote: bool = False ) -> "WikipediaPage": """ Constructs Wikipedia page with title `title`. This function is an alias for :func:`page` :param title: page title as used in Wikipedia URL :param ns: :class:`WikiNamespace` :param unquote: if true it will unquote title :return: object representing :class:`WikipediaPage` """ return self.page( title=title, ns=ns, unquote=unquote, ) def extracts(self, page: "WikipediaPage", **kwargs) -> str: """ Returns summary of the page with respect to parameters Parameter `exsectionformat` is taken from `Wikipedia` constructor. API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bextracts - https://www.mediawiki.org/wiki/Extension:TextExtracts#API Example:: import wikipediaapi wiki = wikipediaapi.Wikipedia('en') page = wiki.page('Python_(programming_language)') print(wiki.extracts(page, exsentences=1)) print(wiki.extracts(page, exsentences=2)) :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: summary of the page """ params = { "action": "query", "prop": "extracts", "titles": page.title, } # type: dict[str, Any] if self.extract_format == ExtractFormat.HTML: # we do nothing, when format is HTML pass elif self.extract_format == ExtractFormat.WIKI: params["explaintext"] = 1 params["exsectionformat"] = "wiki" used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) pages = raw["query"]["pages"] for k, v in pages.items(): if k == "-1": page._attributes["pageid"] = -1 return "" return self._build_extracts(v, page) return "" def info(self, page: "WikipediaPage") -> "WikipediaPage": """ https://www.mediawiki.org/w/api.php?action=help&modules=query%2Binfo https://www.mediawiki.org/wiki/API:Info """ params = { "action": "query", "prop": "info", "titles": page.title, "inprop": "|".join( [ "protection", "talkid", "watched", "watchers", "visitingwatchers", "notificationtimestamp", "subjectid", "url", "readable", "preload", "displaytitle", "varianttitles", ] ), } raw = self._query(page, params) self._common_attributes(raw["query"], page) pages = raw["query"]["pages"] for k, v in pages.items(): if k == "-1": page._attributes["pageid"] = -1 return page return self._build_info(v, page) return page def langlinks(self, page: "WikipediaPage", **kwargs) -> PagesDict: """ Returns langlinks of the page with respect to parameters API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Blanglinks - https://www.mediawiki.org/wiki/API:Langlinks :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: links to pages in other languages """ params = { "action": "query", "prop": "langlinks", "titles": page.title, "lllimit": 500, "llprop": "url", } used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) pages = raw["query"]["pages"] for k, v in pages.items(): if k == "-1": page._attributes["pageid"] = -1 return {} return self._build_langlinks(v, page) return {} def links(self, page: "WikipediaPage", **kwargs) -> PagesDict: """ Returns links to other pages with respect to parameters API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Blinks - https://www.mediawiki.org/wiki/API:Links :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: links to linked pages """ params = { "action": "query", "prop": "links", "titles": page.title, "pllimit": 500, } used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) pages = raw["query"]["pages"] for k, v in pages.items(): if k == "-1": page._attributes["pageid"] = -1 return {} while "continue" in raw: params["plcontinue"] = raw["continue"]["plcontinue"] raw = self._query(page, params) v["links"] += raw["query"]["pages"][k]["links"] return self._build_links(v, page) return {} def backlinks(self, page: "WikipediaPage", **kwargs) -> PagesDict: """ Returns backlinks from other pages with respect to parameters API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bbacklinks - https://www.mediawiki.org/wiki/API:Backlinks :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: backlinks from other pages """ params = { "action": "query", "list": "backlinks", "bltitle": page.title, "bllimit": 500, } used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) v = raw["query"] while "continue" in raw: params["blcontinue"] = raw["continue"]["blcontinue"] raw = self._query(page, params) v["backlinks"] += raw["query"]["backlinks"] return self._build_backlinks(v, page) def categories(self, page: "WikipediaPage", **kwargs) -> PagesDict: """ Returns categories for page with respect to parameters API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bcategories - https://www.mediawiki.org/wiki/API:Categories :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: categories for page """ params = { "action": "query", "prop": "categories", "titles": page.title, "cllimit": 500, } used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) pages = raw["query"]["pages"] for k, v in pages.items(): if k == "-1": page._attributes["pageid"] = -1 return {} return self._build_categories(v, page) return {} def categorymembers(self, page: "WikipediaPage", **kwargs) -> PagesDict: """ Returns pages in given category with respect to parameters API Calls for parameters: - https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bcategorymembers - https://www.mediawiki.org/wiki/API:Categorymembers :param page: :class:`WikipediaPage` :param kwargs: parameters used in API call :return: pages in given category """ params = { "action": "query", "list": "categorymembers", "cmtitle": page.title, "cmlimit": 500, } used_params = kwargs used_params.update(params) raw = self._query(page, used_params) self._common_attributes(raw["query"], page) v = raw["query"] while "continue" in raw: params["cmcontinue"] = raw["continue"]["cmcontinue"] raw = self._query(page, params) v["categorymembers"] += raw["query"]["categorymembers"] return self._build_categorymembers(v, page) def _query(self, page: "WikipediaPage", params: dict[str, Any]): """Queries Wikimedia API to fetch content.""" base_url = "https://" + page.language + ".wikipedia.org/w/api.php" used_params = self._construct_params(page, params) log.info( "Request URL: %s", base_url + "?" + "&".join([k + "=" + str(v) for k, v in used_params.items()]), ) r = self._session.get(base_url, params=used_params, **self._request_kwargs) return r.json() def _construct_params( self, page: "WikipediaPage", params: dict[str, Any] ) -> dict[str, Any]: used_params = {} # type: dict[str, Any] if page.variant: used_params["variant"] = page.variant used_params["format"] = "json" used_params["redirects"] = 1 used_params.update(params) if self._extra_api_params: used_params.update(self._extra_api_params) return used_params def _build_extracts(self, extract, page: "WikipediaPage") -> str: """Constructs summary of given page.""" page._summary = "" page._section_mapping = defaultdict(list) self._common_attributes(extract, page) section_stack = [page] section = None prev_pos = 0 for match in re.finditer(RE_SECTION[self.extract_format], extract["extract"]): if len(page._section_mapping) == 0: page._summary = extract["extract"][0 : match.start()].strip() elif section is not None: section._text = (extract["extract"][prev_pos : match.start()]).strip() section = self._create_section(match) sec_level = section.level + 1 if sec_level > len(section_stack): section_stack.append(section) elif sec_level == len(section_stack): section_stack.pop() section_stack.append(section) else: for _ in range(len(section_stack) - sec_level + 1): section_stack.pop() section_stack.append(section) section_stack[len(section_stack) - 2]._section.append(section) # section_stack[sec_level - 1]._section.append(section) prev_pos = match.end() page._section_mapping[section.title].append(section) # pages without sections have only summary if page._summary == "": page._summary = extract["extract"].strip() if prev_pos > 0 and section is not None: section._text = extract["extract"][prev_pos:] return page._summary def _create_section(self, match): """Creates section.""" sec_title = "" sec_level = 2 if self.extract_format == ExtractFormat.WIKI: sec_title = match.group(2).strip() sec_level = len(match.group(1)) elif self.extract_format == ExtractFormat.HTML: sec_title = match.group(5).strip() sec_level = int(match.group(1).strip()) section = WikipediaPageSection(self, sec_title, sec_level - 1) return section def _build_info(self, extract, page: "WikipediaPage") -> "WikipediaPage": """Builds page from API call info.""" self._common_attributes(extract, page) for k, v in extract.items(): page._attributes[k] = v return page def _build_langlinks(self, extract, page) -> PagesDict: """Builds page from API call langlinks.""" page._langlinks = {} self._common_attributes(extract, page) for langlink in extract.get("langlinks", []): p = WikipediaPage( wiki=self, title=langlink["*"], ns=Namespace.MAIN, language=langlink["lang"], url=langlink["url"], ) page._langlinks[p.language] = p return page._langlinks def _build_links(self, extract, page) -> PagesDict: """Builds page from API call links.""" page._links = {} self._common_attributes(extract, page) for link in extract.get("links", []): page._links[link["title"]] = WikipediaPage( wiki=self, title=link["title"], ns=int(link["ns"]), language=page.language, variant=page.variant, ) return page._links def _build_backlinks(self, extract, page) -> PagesDict: """Builds page from API call backlinks.""" page._backlinks = {} self._common_attributes(extract, page) for backlink in extract.get("backlinks", []): page._backlinks[backlink["title"]] = WikipediaPage( wiki=self, title=backlink["title"], ns=int(backlink["ns"]), language=page.language, variant=page.variant, ) return page._backlinks def _build_categories(self, extract, page) -> PagesDict: """Builds page from API call categories.""" page._categories = {} self._common_attributes(extract, page) for category in extract.get("categories", []): page._categories[category["title"]] = WikipediaPage( wiki=self, title=category["title"], ns=int(category["ns"]), language=page.language, variant=page.variant, ) return page._categories def _build_categorymembers(self, extract, page) -> PagesDict: """Builds page from API call categorymembers.""" page._categorymembers = {} self._common_attributes(extract, page) for member in extract.get("categorymembers", []): p = WikipediaPage( wiki=self, title=member["title"], ns=int(member["ns"]), language=page.language, variant=page.variant, ) p.pageid = member["pageid"] # type: ignore page._categorymembers[member["title"]] = p return page._categorymembers @staticmethod def _common_attributes(extract, page: "WikipediaPage"): """Fills in common attributes for page.""" common_attributes = ["title", "pageid", "ns", "redirects"] for attr in common_attributes: if attr in extract: page._attributes[attr] = extract[attr] @staticmethod def _check_and_correct_params( language: Optional[str], variant: Optional[str], user_agent: Optional[str] ) -> tuple[str, Optional[str], str]: """ Checks the constructor parameters and throws AssertionError if they are incorrect. Otherwise, it normalises them to easy use later on. :param language: Language mutation of Wikipedia :param variant: Language variant :param user_agent: HTTP User-Agent used in requests :return: tuple of language, variant, user_agent """ if not user_agent or len(user_agent) < MIN_USER_AGENT_LEN: raise AssertionError( "Please, be nice to Wikipedia and specify user agent - " + "https://meta.wikimedia.org/wiki/User-Agent_policy. Current user_agent: '" + str(user_agent) + "' is not sufficient. " + "Use Wikipedia(user_agent='your-user-agent', language='" + (str(user_agent) or "your-language") + "')" ) if not language: raise AssertionError( "Specify language. Current language: '" + str(language) + "' is not sufficient. " + "Use Wikipedia(user_agent='" + str(user_agent) + "', language='your-language')" ) used_language = language.strip().lower() if len(used_language) > MAX_LANG_LEN: log.warning( "Used language '%s' is longer than %d. It is suspicious", used_language, MAX_LANG_LEN, ) return ( used_language, variant.strip().lower() if variant else variant, user_agent, ) class WikipediaPageSection: """WikipediaPageSection represents section in the page.""" def __init__( self, wiki: Wikipedia, title: str, level: int = 0, text: str = "" ) -> None: """Constructs WikipediaPageSection.""" self.wiki = wiki self._title = title self._level = level self._text = text self._section = [] # type: list['WikipediaPageSection'] @property def title(self) -> str: """ Returns title of the current section. :return: title of the current section """ return self._title @property def level(self) -> int: """ Returns indentation level of the current section. :return: indentation level of the current section """ return self._level @property def text(self) -> str: """ Returns text of the current section. :return: text of the current section """ return self._text @property def sections(self) -> list["WikipediaPageSection"]: """ Returns subsections of the current section. :return: subsections of the current section """ return self._section def section_by_title(self, title: str) -> Optional["WikipediaPageSection"]: """ Returns subsections of the current section with given title. :param title: title of the subsection :return: subsection if it exists """ sections = [s for s in self._section if s.title == title] if sections: return sections[-1] return None def full_text(self, level: int = 1) -> str: """ Returns text of the current section as well as all its subsections. :param level: indentation level :return: text of the current section as well as all its subsections """ res = "" if self.wiki.extract_format == ExtractFormat.WIKI: res += self.title elif self.wiki.extract_format == ExtractFormat.HTML: res += f"<h{level}>{self.title}</h{level}>" else: raise NotImplementedError("Unknown ExtractFormat type") res += "\n" res += self._text if len(self._text) > 0: res += "\n\n" for sec in self.sections: res += sec.full_text(level + 1) return res def __repr__(self): return "Section: {} ({}):\n{}\nSubsections ({}):\n{}".format( self._title, self._level, self._text, len(self._section), "\n".join(map(repr, self._section)), ) class WikipediaPage: """ Represents Wikipedia page. Except properties mentioned as part of documentation, there are also these properties available: * `fullurl` - full URL of the page * `canonicalurl` - canonical URL of the page * `pageid` - id of the current page * `displaytitle` - title of the page to display * `talkid` - id of the page with discussion """ ATTRIBUTES_MAPPING = { "language": [], "variant": [], "pageid": ["info", "extracts", "langlinks"], "ns": ["info", "extracts", "langlinks"], "title": ["info", "extracts", "langlinks"], "contentmodel": ["info"], "pagelanguage": ["info"], "pagelanguagehtmlcode": ["info"], "pagelanguagedir": ["info"], "touched": ["info"], "lastrevid": ["info"], "length": ["info"], "protection": ["info"], "restrictiontypes": ["info"], "watchers": ["info"], "visitingwatchers": ["info"], "notificationtimestamp": ["info"], "talkid": ["info"], "fullurl": ["info"], "editurl": ["info"], "canonicalurl": ["info"], "readable": ["info"], "preload": ["info"], "displaytitle": ["info"], "varianttitles": ["info"], } def __init__( self, wiki: Wikipedia, title: str, ns: WikiNamespace = Namespace.MAIN, language: str = "en", variant: Optional[str] = None, url: Optional[str] = None, ) -> None: self.wiki = wiki self._summary = "" # type: str self._section = [] # type: list[WikipediaPageSection] self._section_mapping = {} # type: dict[str, list[WikipediaPageSection]] self._langlinks = {} # type: PagesDict self._links = {} # type: PagesDict self._backlinks = {} # type: PagesDict self._categories = {} # type: PagesDict self._categorymembers = {} # type: PagesDict self._called = { "extracts": False, "info": False, "langlinks": False, "links": False, "backlinks": False, "categories": False, "categorymembers": False, } self._attributes = { "title": title, "ns": namespace2int(ns), "language": language, "variant": variant, } # type: dict[str, Any] if url is not None: self._attributes["fullurl"] = url def __getattr__(self, name): if name not in self.ATTRIBUTES_MAPPING: return self.__getattribute__(name) if name in self._attributes: return self._attributes[name] for call in self.ATTRIBUTES_MAPPING[name]: if not self._called[call]: self._fetch(call) return self._attributes[name] @property def language(self) -> str: """ Returns language of the current page. :return: language """ return str(self._attributes["language"]) @property def variant(self) -> Optional[str]: """ Returns language variant of the current page. :return: language variant """ v = self._attributes["variant"] return str(v) if v else None @property def title(self) -> str: """ Returns title of the current page. :return: title """ return str(self._attributes["title"]) @property def namespace(self) -> int: """ Returns namespace of the current page. :return: namespace """ return int(self._attributes["ns"]) def exists(self) -> bool: """ Returns `True` if the current page exists, otherwise `False`. :return: if current page existst or not """ return bool(self.pageid != -1) @property def summary(self) -> str: """ Returns summary of the current page. :return: summary """ if not self._called["extracts"]: self._fetch("extracts") return self._summary @property def sections(self) -> list[WikipediaPageSection]: """ Returns all sections of the curent page. :return: List of :class:`WikipediaPageSection` """ if not self._called["extracts"]: self._fetch("extracts") return self._section def section_by_title( self, title: str, ) -> Optional[WikipediaPageSection]: """ Returns last section of the current page with given `title`. :param title: section title :return: :class:`WikipediaPageSection` """ if not self._called["extracts"]: self._fetch("extracts") sections = self._section_mapping.get(title) if sections: return sections[-1] return None def sections_by_title( self, title: str, ) -> list[WikipediaPageSection]: """ Returns all section of the current page with given `title`. :param title: section title :return: :class:`WikipediaPageSection` """ if not self._called["extracts"]: self._fetch("extracts") sections = self._section_mapping.get(title) if sections is None: return [] return sections @property def text(self) -> str: """ Returns text of the current page. :return: text of the current page """ txt = self.summary if len(txt) > 0: txt += "\n\n" for sec in self.sections: txt += sec.full_text(level=2) return txt.strip() @property def langlinks(self) -> PagesDict: """ Returns all language links to pages in other languages. This is wrapper for: * https://www.mediawiki.org/w/api.php?action=help&modules=query%2Blanglinks * https://www.mediawiki.org/wiki/API:Langlinks :return: :class:`PagesDict` """ if not self._called["langlinks"]: self._fetch("langlinks") return self._langlinks @property def links(self) -> PagesDict: """ Returns all pages linked from the current page. This is wrapper for: * https://www.mediawiki.org/w/api.php?action=help&modules=query%2Blinks * https://www.mediawiki.org/wiki/API:Links :return: :class:`PagesDict` """ if not self._called["links"]: self._fetch("links") return self._links @property def backlinks(self) -> PagesDict: """ Returns all pages linking to the current page. This is wrapper for: * https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bbacklinks * https://www.mediawiki.org/wiki/API:Backlinks :return: :class:`PagesDict` """ if not self._called["backlinks"]: self._fetch("backlinks") return self._backlinks @property def categories(self) -> PagesDict: """ Returns categories associated with the current page. This is wrapper for: * https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bcategories * https://www.mediawiki.org/wiki/API:Categories :return: :class:`PagesDict` """ if not self._called["categories"]: self._fetch("categories") return self._categories @property def categorymembers(self) -> PagesDict: """ Returns all pages belonging to the current category. This is wrapper for: * https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bcategorymembers * https://www.mediawiki.org/wiki/API:Categorymembers :return: :class:`PagesDict` """ if not self._called["categorymembers"]: self._fetch("categorymembers") return self._categorymembers def _fetch(self, call) -> "WikipediaPage": """Fetches some data?.""" getattr(self.wiki, call)(self) self._called[call] = True return self def __repr__(self): r = f"{self.title} (lang: {self.language}, variant: {self.variant}, " if any(self._called.values()): r += f"id: {self.pageid}, " else: r += "id: ??, " r += f"ns: {self.ns})" return r

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kaman05010/MCPClientServer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server