基于lxml和Selenium包,以JSON为查询结构,基于python构建的数据检索Web引擎。
dr-web-engine的Python项目详细描述
数据检索Web引擎
上下文
多种技术被用作web解析器、web scraper、spider等等。 比较研究可以在literature中找到 根据方法和技术进行分类。我们从另一个角度来看^{str1}$queryability特性。 我们的灵感来自于OXPath,其中XPath的扩展用于从web“查询”和提取半结构化数据。在
目标
与OXPath类似,我们的目标是创建一个基于“查询”机制的web数据检索工具。 我们选择在查询定义中使用JSON构造,并增加关键字、过滤器和操作。在
技术堆栈
这个工具是用Python3编写的,可以通过从python包索引安装它来包含在其他python项目中
使用pip3 install dr-web-engine
或通过运行python3 -m web_engine.runner
与工具命令行界面集成
该工具是建立在其他几个软件包之上,这些软件包将自动安装。这些是:
- 硒
- Geckodriver自动安装程序
- LXML公司
- Python接口
- 阿尔格帕斯
- xvfbw抓取器
XVFB只在Linux上工作,如果参数在Windows或MacOX系统上为True,则会收到一条错误消息。在
Python包页面可以找到here
使用
要使用集成的CLI,请运行python3 -m web_engine.runner
。这将显示以下帮助消息:
usage: runner.py [-h][-q QUERY][-e [ENGINE]][-ht [HEIGHT]][-wh [WIDTH]][-lat [LAT]][-lon [LON]][-img [IMG]][-l [LOG]][-xvfb [XVFB]] Web Scrap Engine for semi-structured web data retrieval using JSON query constructs optional arguments: -h, --help show this help message and exit -q QUERY, --query QUERY JSON query -e [ENGINE], --engine [ENGINE] Engine: use [lxml]for parser engine (default), [selenium]for action based web scraping -ht [HEIGHT], --height [HEIGHT] specify the browser window height (default is 800, only used with Selenium engine) -wh [WIDTH], --width [WIDTH] specify the browser window width (default is 1280, only used with Selenium engine) -lat [LAT], --lat [LAT] Latitude (not specified by default) -lon [LON], --lon [LON] Longitude (not specified by default) -img [IMG], --img [IMG] Load images -l [LOG], --log [LOG] Set flag to True to see verbose logging output -xvfb [XVFB], --xvfb [XVFB] Set flag to False to see Firefox when using Selenium engine
只有一个必需的参数:-q Query
例如,要使用以下JSON查询(假定为文件test.json
)运行web数据检索:
使用以下命令:python3 -m web_engine.runner -q test.json
。结果将类似于以下JSON结果:
{"links": [{"link": ["https://en.wikipedia.org/wiki/Donald_Duck"], "title": ["Donald Duck - Wikipedia"]}, {"link": ["https://cosleyzoo.org/white-pekin-duck/"], "title": ["White Pekin Duck – Cosley Zoo"]}, {"link": ["https://www.cheatsheet.com/entertainment/donald-duck-turned-85-years-old.html/"], "title": ["Donald Duck Turned 85-Years-Old and Disney Fans Are Quacking ..."]}, {"link": ["https://en.wikipedia.org/wiki/Daisy_Duck"], "title": ["Daisy Duck - Wikipedia"]}, {"link": ["https://www.headstuff.org/culture/history/disney-studios-war-story-donald-duck-became-sgt/"], "title": ["Disney Studios At War - the story of how Donald Duck became a Sgt ..."]}
{JSON>和操作可以在cd7>或操作中提供。 如果我们删除所有关键字,剩下的JSON表示预期输出的结构。在
在另一个更复杂的查询中,我们使用一些其他关键字和操作:
{"_doc":"https://www.checkatrade.com/trades/WayreHouseElectricalServices","data":{"ld_data":"//head/script[@type=\"application/ld+json\"][1]"},"reviews":[{"_doc":"https://www.checkatrade.com/trades/WayreHouseElectricalServices/reviews","_base_path":"//div[contains(@class, 'ReviewsPage__Content')]//div[contains(@class, 'ReviewsItem__Wrapper')]","_key":"review","_pre_remove":"//*[contains(@class,'alert-box')]","_follow":"//a[contains(@class,\"Chevrons__Wrapper\")][2]/@href","_follow_action":"//a[contains(@class,\"Chevrons__Wrapper\")][2]{click }","title":"//h3[contains(@class, 'ReviewsItem__Title')]","score":"//*[name()='svg']//text()[normalize-space()]","verified":"//div[contains(@class, 'ReviewsItem__Verified')]/text()[normalize-space()]","content":"//p[contains(@class, 'ReviewsItem__P')]","review_by":"//div[contains(@class, 'ReviewsItem__Byline')]/text()[normalize-space()]"}]}
关键词
_doc
:表示要遵循的文档。通常是指向网页的URL。它在顶层是强制性的,可以在层级结构的较低层级提供。_doc
关键字
_base_path
:用于数组提取。数组是元素的列表,在查询中定义为JSON数组[]
。
当提供_base_path
时,数组中查询的所有元素都将在由_base_path
定义的HTML元素内查找。在
_key
:用于将数组中的每个元素分配给变量_key
_pre_xxx
:所有以_pre_
开头的操作都将在数据提取之前执行。在
_pre_remove
:从页面中删除元素
_follow
:如果存在,请跟随链接
_follow_action
:如果follow中的元素存在,则执行操作而不是跟随链接。这些操作被定义为XPath查询的最后一部分,并且总是在carley方括号之间定义。在本例中,操作{click }
表示单击元素。在
可扩展性
这个包是为了便于扩展。例如,{click }
操作在查询中定义如下:
对应定义如下:
classClickAction(implements(Action)):def__init__(self,receiver,log:logging=None):self._log=logself._receiver=receiverdefexecute(self,*args):ifargsisNoneorlen(args)!=1:returnxpath_selector:str=args[0]wait=WebDriverWait(self._receiver.driver,10)elem=wait.until(EC.element_to_be_clickable((By.XPATH,xpath_selector)))elem.click()
在Scraper实现中,针对关键字注册操作,如下所示:
click=ClickAction(self,self.log)filter_remove=FilterRemoveAction(self,self.log)self.register('click',click)self.register('remove',filter_remove)
只需匹配查询中的action关键字即可调用,如下所示:
defaction_get(self,actions:list):forxinactions:self.execute(x)returnself.get()defexecute(self,action_composite:str):action_name,action_path=SeleniumScraper.__get_action(action_composite)action_name=action_name.strip()ifaction_nameinself._actions.keys():self._history.append((time.time(),action_name))self._actions[action_name].execute(action_path)else:self.log.warn(f"Command [{action_name}] not recognised")@staticmethoddef__get_action(action_composite):pattern='{(.+?)}'matches=re.search(pattern,action_composite)ifnotmatches:returnNone,Noneaction_name=matches.group(1)action_xpath=re.sub(pattern,'',action_composite)returnaction_name,action_xpath
今后的工作
这项工作,虽然它是一个正在工作的测试版,但绝不是完整的,它只是集中在一个狭隘的特定问题上。然而,为了使解决方案具有通用性、通用性和可扩展性,已经做出了特别的努力,使其有可能成长为一个成熟的基于JSON查询的数据检索Web引擎。在
- 项目
标签: