55
66import aiohttp
77import bs4
8+ import re
89
910
11+ from contextlib import suppress
12+ from core .decorators import in_executor # type: ignore
1013from typing import Any , Optional , List
1114from urllib .parse import quote_plus
12- from core .decorators import in_executor # type: ignore
1315
1416
1517class SearchResult :
@@ -22,7 +24,16 @@ def __repr__(self) -> str:
2224 return f"<{ self .__class__ .__name__ } link={ self .link } title={ self .title } contents={ self .contents } >"
2325
2426 def __eq__ (self , other : Any ) -> bool :
25- return isinstance (other , SearchResult ) and (self .title == other .title and self .contents == other .contents )
27+ return isinstance (other , SearchResult ) and (
28+ self .title == other .title and self .contents == other .contents
29+ )
30+
31+
32+ class SpecialResult :
33+ def __init__ (self , type : str , content : Any ) -> None :
34+ self .type : str = type
35+ self .content : Any = content
36+ pass
2637
2738
2839class ComplementaryResult :
@@ -61,37 +72,59 @@ def parseResults(self, page: str) -> Optional[dict]:
6172 # normal results
6273 results = soup .find ("div" , {"id" : "search" }).find_all ("div" , {"class" : "g" }) # type: ignore
6374 webRes : Optional [List [SearchResult ]] = None
75+ specialRes : Optional [SpecialResult ] = None
76+ # parse both webRes and specialRes (if there is)
6477 if results :
6578 webRes = []
6679 for result in results :
6780 try :
6881 link = result .find ("a" , href = True )["href" ] # type: ignore
6982 except (KeyError , TypeError ):
7083 continue
71- title = result .find ("h3" ).text # type: ignore
72- summary = result .find ("div" ).select ("div > span" ) # type: ignore
73- if summary and title and link :
74- res = SearchResult (link , title , [s .text for s in summary [1 :]])
75- if res not in webRes :
76- webRes .append (res )
84+ try :
85+ title = result .find ("h3" ).text # type: ignore
86+ except AttributeError :
87+ # Special result such as Currency converter, Maps, etc
88+ type = result .find ("h2" ).text # type: ignore
89+
90+ if type == "Currency converter" :
91+ contents = result .find ( # type: ignore
92+ "div" , id = re .compile ("knowledge-currency" )
93+ ).contents
94+ formattedContent = []
95+
96+ # Currency stuff
97+ convertion = contents [0 ].find_all ("div" )
98+ target = f"`{ convertion [0 ].text } `"
99+ dest = convertion [1 ].find_all ("span" )
100+ dest = f"**`{ dest [0 ].text } ` { dest [1 ].text } **"
101+ formattedContent .extend ([target , dest ])
102+
103+ # Last updated
104+ formattedContent .append (contents [1 ].text )
105+ specialRes = SpecialResult (type , formattedContent )
106+
107+ continue
108+ else :
109+ summary = result .find ("div" ).select ("div > span" ) # type: ignore
110+ if summary and title and link :
111+ res = SearchResult (link , title , [s .text for s in summary [1 :]])
112+ if res not in webRes :
113+ webRes .append (res )
77114
78115 # Complementary results
79116 complementaryRes = soup .find ("div" , {"id" : "rhs" , "data-hveid" : True })
80117 if complementaryRes :
81- try :
82- title = complementaryRes .find ("h2" , {"data-attrid" : "title" }).span .text # type: ignore
83- except AttributeError :
84- title = None
118+ title : Optional [str ] = None
119+ subtitle : Optional [str ] = None
120+ desc : Optional [str ] = None
85121
86- try :
122+ with suppress (AttributeError ):
123+ title = complementaryRes .find ("h2" , {"data-attrid" : "title" }).span .text # type: ignore
87124 subtitle = complementaryRes .find ("div" , {"data-attrid" : "subtitle" }).span .text # type: ignore
88- except AttributeError :
89- subtitle = None
90125
91- try :
126+ with suppress ( AttributeError ) :
92127 desc = complementaryRes .find ("div" , {"class" : "kno-rdesc" }).span .text # type: ignore
93- except AttributeError :
94- desc = None
95128
96129 infoList = complementaryRes .find_all ("div" , {"data-attrid" : True , "lang" : True }) # type: ignore
97130 formattedInfo = []
@@ -110,12 +143,20 @@ def parseResults(self, page: str) -> Optional[dict]:
110143 if infoTitle and infoContent :
111144 formattedInfo .append ((infoTitle , infoContent ))
112145
146+ # A complementary result always have title and subtitle
113147 if subtitle and title :
114- complementaryRes = ComplementaryResult (title , subtitle , desc , formattedInfo )
148+ complementaryRes = ComplementaryResult (
149+ title , subtitle , desc , formattedInfo
150+ )
115151 else :
116152 complementaryRes = None
117153
118- return {"stats" : searchStats , "web" : webRes , "complementary" : complementaryRes }
154+ return {
155+ "stats" : searchStats ,
156+ "web" : webRes ,
157+ "complementary" : complementaryRes ,
158+ "special" : specialRes ,
159+ }
119160
120161 async def search (
121162 self ,
0 commit comments