Python學(xué)習(xí)筆記-第20天:異步爬蟲(chóng)(2)

第二十天 異步爬蟲(chóng)(2)

今天計(jì)劃用Python開(kāi)發(fā)一套異步爬蟲(chóng)框架用來(lái)補(bǔ)充blog內(nèi)容,學(xué)習(xí)項(xiàng)目及練習(xí)源碼地址:
GitHub源碼

在蜘蛛中提取想要的數(shù)據(jù)

lxml

通過(guò)lxml模塊分析爬取到的頁(yè)面數(shù)據(jù),提取想要的內(nèi)容。

封裝一個(gè)selector類

from lxml import etree
from lxml.html import fromstring, tostring
from pyquery import PyQuery as pq

class Xpath(Selector):
    def parse_detail(self, html):
        d = etree.HTML(html)
        try:
            if self.attr is None:
                result = None
                if len(d.xpath(self.rule)) > 1:
                    result =  [entry for entry in d.xpath(self.rule)]
                else:
                    result = d.xpath(self.rule)

                if self.r_type == 'elstr' and len(result) > 0:
                    return [tostring(el,'utf-8').decode('utf-8') for el in result]
                elif self.r_type == 'text' and len(result) >0:
                    return [el.text for el in result]
                else:
                    return result

            return [entry.get(self.attr, None) for entry in d.xpath(self.rule)] if len(d.xpath(self.rule)) > 1 else \
                d.xpath(self.rule)[0]
        except IndexError:
            return None

要點(diǎn):

  • lxml.etree 提供的xpath獲取頁(yè)面元素
  • tostring(el,'utf-8').decode('utf-8') 直接提取某元素內(nèi)的html內(nèi)容

在蜘蛛中使用:

 async def parser(self,data):
        try:
            # print('jianshu parser',data)
            title = Xpath('//section/h1/text()').parse_detail(data)[0]    
            content = Xpath('//*[@id="__next"]/div[1]/div/div/section[1]/article',r_type='elstr').parse_detail(data)[0]        
        except BaseException as e:
            self.logger.error(e)

自此,已經(jīng)完成了蜘蛛對(duì)頁(yè)面的爬取,以及數(shù)據(jù)的解析。

讓蜘蛛定時(shí)爬取

在crawler函數(shù)中回調(diào)自身

async def crawler(self):
        await self.init_spiders()
        workers = [asyncio.Task(self.worker(), loop=self.loop)
                   for _ in range(self.max_tasks)]
        await self.q.join()

        for w in workers:
            w.cancel()
        await asyncio.sleep(5 * 60)
        await self.crawler() # 重新一直運(yùn)行下去

注意:到目前為止,發(fā)現(xiàn)這樣的方式有一點(diǎn)問(wèn)題,不知道是否可以像nodejs一樣可以尾回調(diào),因?yàn)橐恢被卣{(diào)會(huì)導(dǎo)致嵌套過(guò)深的問(wèn)題。

蜘蛛的啟動(dòng)

在啟動(dòng)中可以初始化一些輔助的服務(wù),如mysql連擊池等

def main(loop):
    print('starting kospider server')
    coros = [mysql.initpool(loop=loop), redis.init_pool(loop=loop)]
    loop.run_until_complete(asyncio.gather(*coros))
    
    engine = Engine(loop=loop)
    engine.run()

event_loop = asyncio.get_event_loop()
try:
    event_loop.run_until_complete(main(event_loop))
    print('stoped kospider server')
except BaseException as e:
    print('Main error',e)
finally:
    event_loop.close()    # 當(dāng)輪訓(xùn)器關(guān)閉以后,所有沒(méi)有執(zhí)行完成的協(xié)成將全部關(guān)閉

明天正式將數(shù)據(jù)寫入數(shù)據(jù)庫(kù),并在頁(yè)面顯示內(nèi)容。

計(jì)劃找一個(gè)能讓蜘蛛定時(shí)執(zhí)行的好方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容