Python爬虫:细说列表识别提取
天冷要保暖
上次文章后不少小伙伴私信我,对此感兴趣,希望我讲讲列表识别的细节问题。于是有了今天这篇文章。还是先再提一下本算法的核心思想。
- 排列规则的链接为可以列表块。
- 列表块范围在主视图区域内为目标列表。
先看下识别结果:
列表识别结果图
提取列表区域xpath宏观分成三个大步骤
1.可疑列表区域提取
在进行可疑列表区域提取之前需要做一些预处理:因为selenium只能定位到页面上的可见元素,所以先用selenium的find_elements_by_xpath("//a")
获取所有可见的<a>,并对定位到的元素创建新属性canSee并赋值yeap:self.__web_driver.execute_script("arguments[0].setAttribute('can-see','yeap');", link)
(其实你想属性叫什么就叫什么),然后就清洗完毕了。
接下来用lxml库的etree定位到dom树(这里将html直接说成dom树是为了后面提取最小父节点时候好理解)上所有canSee属性是True的<a>标签节点。将该节点假如列表A,以三个元素为单位扫描该列表,如下图。
可疑列表区域扫描过程示意图
Tips:
- 在整个dom树下,同一子树同一层级的节点才会提取最小父节点(最小父节点:层级尽可能的小)
- 重复父节点的xpath不要重复计入
- 有的<a>标签下取text会出现问题,最好用xpath的string(.)方式
- 元素清洗时可以初步匹配明显反向特征,匹配成功直接退出
在三大步骤中,只有这一步是在做加法,剩下的步骤基本是在过滤做减法了,所以尽可能的将可疑列表区域收入列表。
代码流程参考:
def tag_a_min_father_node(self): """ 计算提取可疑列表区域 :return: [xpath1,xpath2,xpath3,...] """ links_Ele = [] father_list = [] # 预处理-将可见<a>设置属性can-see self.watch_links() root = etree.HTML(self.driver.page_source) Eleroot = etree.ElementTree(root) temp_total_path = [] links = Eleroot.findall('//a[@cansee]') self.LOG.info("all links after filter: {}".format(len(links))) # 识别时忽略JavaScript,因为后续步骤没有上下文环境 links_Ele = [(x.xpath("string(.)")..strip(),\ Eleroot.getpath(x), \ x.attrib.get("href","")) \ for x in links \ if x.xpath("string(.)"). and len(x.xpath("string(.)").strip()) > 1 and \ self.anchor_black_regx.search(x.xpath("string(.)").strip()) is None\ and self.debar_extension_name_regex.search(x.attrib.get("href","")) is None \ and not x.attrib.get("href","").startswith("java")\ and not x.attrib.get("href","").startswith("#") # 不要锚链接 ] # 元素清洗 # 相邻标签相同href,合并 # 如果匹配到反向特征 legitimate = False legitimate, links_Ele = self.clean_links_Ele(links_Ele) if legitimate: # 扫描有效链接,提取最小父节点xpath for idx in xrange(len(links_Ele)-2): # 每次取三个元素 now = links_Ele[idx: idx+3] is_list, father_xpath = self.get_list_father_xpath(now) if is_list: # 符合列表逻辑 father_list.append(father_xpath) return list(set(father_list))
2.过滤不在主视图区域的可疑列表
- 2.1 校验x轴
在这该步骤中,校验可疑列表区域是否在主视图范围内。你需要了解selenium的location方法,了解(x,y)坐标点在浏览器中的意义,在该算法中,使用x轴中位线作为判断依据。
现有列表区域A,其location为(x1,y1)。列表A中,有最大链接b,其size[‘width’]为x2。若x1+x2 > x轴中位线,则列表A在主视图范围内。
看下图,不难理解:
红线为x轴中位线
代码流程参考:
def judge_list_xpath(self): """ 判断获取到的列表xpath是否在主视图区域 :return:[xpath1,xpath2] """ a_list= [] list_xpath = [] result = [] # 获取可疑列表区域 list_xpath = self.get_page_list() if list_xpath: for item in list_xpath: a_size_list = [] try: a_list = self.driver.find_elements_by_xpath(item + '//a') except: self.LOG.error("{}:{}无法找到该xpath" .format(self.driver.current_url, item + '//a')) for element in a_list: a_size_list.append(element.size['width']) # 有的html可能不规范,会出现定位不到元素的情况 max_a_size = max(a_size_list) if len(a_size_list) > 0 else 0 if max_a_size == 0: continue # 判断size最大的a标签的位置 content = self.driver.find_element_by_xpath(item) # 超过3000认为异常情况 if content.size['width'] > 3000: continue # 这句无所谓,原来想用来过滤导航栏之类的,现在后续有更好解决方案 if (content.size['height']) < 70 and content.size['height'] != 0: continue # 判断x轴中位线 if self.check_x(content): result.append(item) self.LOG.info("list after view filter: {}".format(result)) return result
- 2.2校验y轴
这一步需要放在程序最后,规则也比较简单,最后校验列表的location['y']
是否在浏览器的当前页面中,我认为如果你打开网页,一下看不见列表,需要往下拖才有列表,就不是我们需要的主列表了,可能是混进来奇奇怪怪的东西,逻辑比较简单就不贴代码流程了。
3.可扩展规则簇
以上步骤基本可以保证你获得一个穿过了x中位线的列表区域,但极有可能混进去一些奇奇怪怪的东西,或者漏了一些重要的东西。这时候就需要你的这些规则了,比如:
- 多块列表跨x中位线
- 是否只是一整个列表的分块,如(http://www.chinasafety.gov.cn/newpage/aqbz/aqbz_gjbzgb.htm)需要融合。
- 又或者真的是多个列表,需要过滤,如(http://www.cbrc.gov.cn/shanxi/pcjgMore/601108/left.html)
- 识别到导航栏或者识别到滚动栏中的新闻,不需要这种东西,需要过滤
- 过滤规则很简单,校验xpath中<a>的y坐标,极大值与极小值需要超过一个阀值
- 中央区域含有文本为更多的链接,我相信这种列表也不是我们需要的
还有后续其他的规则往上追加就好OvO
至此列表区域识别已经完成,输出值为列表区域的xpath。
有问题的话私聊我吧,没问题的话点赞吧~
原文地址:https://www.jianshu.com/p/fee79753cf9f
相关推荐
-
python爬虫-36kr网+Django+Echarts图表 网络爬虫
2019-8-29
-
python爬虫学习之查询IP地址对应的归属地 网络爬虫
2019-10-8
-
scrapy结合selenium进行动态加载页面内容爬取 网络爬虫
2019-8-26
-
Python爬虫建站入门手记——从零开始建立采集站点(三:采集入库) 网络爬虫
2018-2-28
-
Python爬虫(2):Requests的基本用法 网络爬虫
2018-3-13
-
python小伙用python抓取百度五福图片 网络爬虫
2019-8-29
-
Python爬虫—破解JS加密的Cookie 网络爬虫
2019-2-22
-
在Scrapy中运用Selenium和Chrome 网络爬虫
2019-8-26
-
如何去高大上的下载电影天堂的内容 网络爬虫
2019-8-25
-
python爬取公众号,用最简单的方式爬虫 网络爬虫
2019-8-25