基于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数据检索:

^{pr2}$

使用以下命令: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引擎。在

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java如何在没有代码气味的情况下编写遵循Liskov替代和其他可靠原则的不可变映射?   java最新jre上的压缩字符串对旧编译代码有好处吗?   java是否可以在javascript中取消PrimeFaces menuitem onclick函数   mysql从SQL数据库中访问java中xml名称空间标记的值   从java程序打开excel文件   java在方法中使用“var”是否会使执行(并发)线程不安全?   java使搜索视图以一种关于AndroidManifest的通用方式可用。xml   java对如何准确使用正则表达式感到困惑?   mule如何访问java文件中的记录变量   java在从2D数组引发异常后继续   枚举当前设置为的java值   java当listview只有几个项目时,如何使alert对话框显示listview的所有项目?   java getTableRow()返回大于项大小的索引   c用java传输二进制文件(数据)   java更改多选列表项复选框颜色