Python爬蟲:細(xì)說列表識(shí)別提取

天冷要保暖

??上次文章后不少小伙伴私信我,對(duì)此感興趣,希望我講講列表識(shí)別的細(xì)節(jié)問題。于是有了今天這篇文章。還是先再提一下本算法的核心思想。

  • 排列規(guī)則的鏈接為可以列表塊。
  • 列表塊范圍在主視圖區(qū)域內(nèi)為目標(biāo)列表。
    先看下識(shí)別結(jié)果:
    列表識(shí)別結(jié)果圖

    提取列表區(qū)域xpath宏觀分成三個(gè)大步驟

1.可疑列表區(qū)域提取

??在進(jìn)行可疑列表區(qū)域提取之前需要做一些預(yù)處理:因?yàn)閟elenium只能定位到頁(yè)面上的可見元素,所以先用selenium的find_elements_by_xpath("http://a")獲取所有可見的<a>,并對(duì)定位到的元素創(chuàng)建新屬性canSee并賦值yeap:self.__web_driver.execute_script("arguments[0].setAttribute('can-see','yeap');", link)(其實(shí)你想屬性叫什么就叫什么),然后就清洗完畢了。
??接下來用lxml庫(kù)的etree定位到dom樹(這里將html直接說成dom樹是為了后面提取最小父節(jié)點(diǎn)時(shí)候好理解)上所有canSee屬性是True的<a>標(biāo)簽節(jié)點(diǎn)。將該節(jié)點(diǎn)假如列表A,以三個(gè)元素為單位掃描該列表,如下圖。

可疑列表區(qū)域掃描過程示意圖

Tips:
  • 在整個(gè)dom樹下,同一子樹同一層級(jí)的節(jié)點(diǎn)才會(huì)提取最小父節(jié)點(diǎn)(最小父節(jié)點(diǎn):層級(jí)盡可能的小
  • 重復(fù)父節(jié)點(diǎn)的xpath不要重復(fù)計(jì)入
  • 有的<a>標(biāo)簽下取text會(huì)出現(xiàn)問題,最好用xpath的string(.)方式
  • 元素清洗時(shí)可以初步匹配明顯反向特征,匹配成功直接退出

??在三大步驟中,只有這一步是在做加法,剩下的步驟基本是在過濾做減法了,所以盡可能的將可疑列表區(qū)域收入列表。

代碼流程參考:
def tag_a_min_father_node(self):
    """
    計(jì)算提取可疑列表區(qū)域        
    :return: [xpath1,xpath2,xpath3,...]
    """
    links_Ele = []
    father_list = []
    # 預(yù)處理-將可見<a>設(shè)置屬性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)))
    # 識(shí)別時(shí)忽略JavaScript,因?yàn)楹罄m(xù)步驟沒有上下文環(huán)境
    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("#") # 不要錨鏈接
                     ]
    # 元素清洗
    # 相鄰標(biāo)簽相同href,合并
    # 如果匹配到反向特征 legitimate = False
    legitimate, links_Ele = self.clean_links_Ele(links_Ele)

    if legitimate:
        # 掃描有效鏈接,提取最小父節(jié)點(diǎn)xpath
        for idx in xrange(len(links_Ele)-2):
            # 每次取三個(gè)元素
            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.過濾不在主視圖區(qū)域的可疑列表

  • 2.1 校驗(yàn)x軸
    ??在這該步驟中,校驗(yàn)可疑列表區(qū)域是否在主視圖范圍內(nèi)。你需要了解selenium的location方法,了解(x,y)坐標(biāo)點(diǎn)在瀏覽器中的意義,在該算法中,使用x軸中位線作為判斷依據(jù)。
    ??現(xiàn)有列表區(qū)域A,其location為(x1,y1)。列表A中,有最大鏈接b,其size['width']為x2。若x1+x2 > x軸中位線,則列表A在主視圖范圍內(nèi)。
    ??看下圖,不難理解:
    紅線為x軸中位線

代碼流程參考:

def judge_list_xpath(self):
    """
    判斷獲取到的列表xpath是否在主視圖區(qū)域
    :return:[xpath1,xpath2]
    """
    a_list= []
    list_xpath = []
    result = []
    # 獲取可疑列表區(qū)域
    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可能不規(guī)范,會(huì)出現(xiàn)定位不到元素的情況
            max_a_size = max(a_size_list) if len(a_size_list) > 0 else 0
            if max_a_size == 0: continue
            # 判斷size最大的a標(biāo)簽的位置
            content = self.driver.find_element_by_xpath(item)
            # 超過3000認(rèn)為異常情況
            if content.size['width'] > 3000:
                continue
            # 這句無所謂,原來想用來過濾導(dǎo)航欄之類的,現(xiàn)在后續(xù)有更好解決方案
            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àn)y軸
    ??這一步需要放在程序最后,規(guī)則也比較簡(jiǎn)單,最后校驗(yàn)列表的location['y']是否在瀏覽器的當(dāng)前頁(yè)面中,我認(rèn)為如果你打開網(wǎng)頁(yè),一下看不見列表,需要往下拖才有列表,就不是我們需要的主列表了,可能是混進(jìn)來奇奇怪怪的東西,邏輯比較簡(jiǎn)單就不貼代碼流程了。

3.可擴(kuò)展規(guī)則簇

??以上步驟基本可以保證你獲得一個(gè)穿過了x中位線的列表區(qū)域,但極有可能混進(jìn)去一些奇奇怪怪的東西,或者漏了一些重要的東西。這時(shí)候就需要你的這些規(guī)則了,比如:

  • 多塊列表跨x中位線
  • 識(shí)別到導(dǎo)航欄或者識(shí)別到滾動(dòng)欄中的新聞,不需要這種東西,需要過濾
    • 過濾規(guī)則很簡(jiǎn)單,校驗(yàn)xpath中<a>的y坐標(biāo),極大值與極小值需要超過一個(gè)閥值
  • 中央?yún)^(qū)域含有文本為更多的鏈接,我相信這種列表也不是我們需要的
    還有后續(xù)其他的規(guī)則往上追加就好OvO

至此列表區(qū)域識(shí)別已經(jīng)完成,輸出值為列表區(qū)域的xpath。
有問題的話私聊我吧,沒問題的話點(diǎn)贊吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評(píng)論 3 422
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,960評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,914評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,089評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,340評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評(píng)論 1 289
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,834評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,106評(píng)論 2 375