Python爬蟲開發與專案實戰——基礎爬蟲分析

eye_water發表於2017-12-27
最近在看《Python爬蟲開發與專案實戰》,看到第六章基礎爬蟲時,發現把實現爬蟲各個功能分別封裝為一個類能增強爬蟲的可讀性,不過理解程式碼時碰到了許多坑,因此分享一下讀書筆記。

書籍第六章的程式碼

程式碼中的註釋給的已經足夠了,但是隻是針對單個檔案,對於整體爬蟲專案,理解起來難免還會有點模糊
這一章爬取的是百度百科,給出一個url通過該頁面的連結爬取其它的url,看起來就像這樣:

這裡寫圖片描述
給出一個Root_Url,看看它都經歷了什麼
Root_url作為整個程式的第一個Url,即為一個新的Url,要加入到Url管理器中

self.manager.add_new_url(root_url)

Root_Url對應的頁面肯定含有其它知識的百科連結,因此要提取,在提取之前要從Url管理器中獲得Root_Url,然後獲取Root_Url對應的頁面的頁面資訊:

new_url = self.manager.get_new_url()
html = self.downloader.download(new_url)
如何從Url管理器中獲取Url?

通過pop()方法每次從Url集合中取一個出來,並把取出的Url標記為已爬取的Url

URLManager.py

class UrlManager(object):
    ...
    def get_new_url(self):
        new_url = self.new_urls.pop()
        self.old_urls.add(new_url)
        return new_url
    ...
如何獲取頁面資訊?

通過requests

HtmlDownloader.py

class HtmlDownloader(object):
    def download(self,url):
        ...
        return r.text
        ...

有了頁面資訊,就可以把其它知識的百科連結提取出來,以及儲存當前頁面知識的資訊:

new_urls,data = self.parser.parser(new_url,html)
怎麼獲取?

通過BeautifulSoup解析HTML文件:

HtmlParser.py

class HtmlParser(object):
    def parser(self,page_url,html_cont):
        ...
        soup = BeautifulSoup(html_cont,'html.parser',from_encoding='utf-8')
        new_urls = self._get_new_urls(page_url,soup)
        new_data = self._get_new_data(page_url,soup)
        ...

    def _get_new_urls(self,page_url,soup):
        links = soup.find_all('a', href=re.compile(r'/item/.*'))
        for link in links:
            new_url = link['href']
            new_full_url = urlparse.urljoin(page_url,new_url)
            new_urls.add(new_full_url)

    def _get_new_data(self,page_url,soup):
        ...
        return data      

如果把Root-Url看作父節點,那麼第一次獲取的Url集合為:
這裡寫圖片描述
獲取到Url集合之後把它儲存到Url管理器中

self.manager.add_new_urls(new_urls)

對於Url管理器來說實際上就是把得到Url集合新增new_urls集合的後面

URLManager.py

class UrlManager(object):
    def __init__(self):
        self.new_urls = set()
    ...

    def add_new_url(self,url):
        if url is None:
            return
        if url not in self.new_urls and url not in self.old_urls:
            self.new_urls.add(url)

    def add_new_urls(self,urls):
        if urls is None or len(urls)==0:
            return
        for url in urls:
            self.add_new_url(url)
    ...

通過BeautifulSoup庫解析後的引數有兩個,new_urls已經處理過了,即加入到Url管理器中了,data還沒處理,需要把它存到檔案中:

self.output.store_data(data)

還要列印當前處理了多少Url,即獲取處理過的Url:

print "已經抓取%s個連結"%self.manager.old_url_size()

相應地,Url管理器是這麼做的:

URLManager.py

class UrlManager(object):
    def __init__(self):
        self.old_urls = set()
    ...

    def old_url_size(self):
        return len(self.old_urls)

這樣一次迴圈就完事了,第二次迴圈呢?
會從第一次由Root_Url產生的子Url中選擇一個進行處理,如此迴圈,有時可能在處理子Url時,還沒處理當前子Url產生的子子Url,就去處理另一個子Url,等等情況。
如果Url所構造的樹為下面這樣該怎麼做呢?
這裡寫圖片描述
很簡單,因為Url-X不會生成子Url,因此在處理Url-x時不獲取該頁面所包含的其它Url即可。
可以參考一下我基於一個下小說的簡易爬蟲改造成多檔案的程式碼,而不在是一個檔案完成所有的功能。
自己寫的程式碼在這

相關文章