1. 程式人生 > >Python爬蟲實戰專案1 | 基礎爬蟲的實現(爬取100條百度百科詞條)

Python爬蟲實戰專案1 | 基礎爬蟲的實現(爬取100條百度百科詞條)

【基礎爬蟲篇】

本篇講解一個比較簡單的Python爬蟲。

這個爬蟲雖然簡單,但五臟俱全,大爬蟲有的模組這個基礎爬蟲都有,只不過大爬蟲做的更全面、多樣。

1.實現的功能:這個爬蟲實現的功能為爬取百度百科中的詞條資訊。爬取的結果見6。

2.背景知識:(1).Python語法;(2).BeautifulSoup;(3).HTML知識;

                       Python基礎語法學習可參看:推薦《Python程式設計——從入門到實踐》,或者廖雪峰Python部落格。

                       BeautifulSoup主要語法可參看:BeautifulSoup主要知識點

3.基礎爬蟲框架及執行流程

基礎爬蟲包括五個模組,分別是爬蟲排程器,URL管理器,HTML下載器,HTML解析器,資料儲存器。
功能分析如下:
(1).爬蟲排程器主要負責統籌其他四個模組的協調工作;
(2).URL管理器負責管理URL連結,維護已經爬取的URL集合和未爬取的URL集合,提供獲取新URL連結的介面;
(3).HTML下載器用於從URL管理器中獲取未爬取的URL連結並下載HTML網頁;
(4).HTML解析器用於從HTML下載器中獲取已經下載的HTML網頁,並從中解析出新的URL連結交給URL管理器,解析出有效資料交給資料儲存器。
(5).資料儲存器用於將HTML解析器解析出來的資料通過檔案或者資料庫的形式解析出來。

檔案組織目錄:

其中__init__.py的內容為空,它的作用簡單說就是讓這個包變成一個模組,身份發生了變化。

1.URL管理器
連結去重複在Python爬蟲開發中是必備的技能,解決方案主要有三種:1).記憶體去重;2).關係資料庫去重;3).快取資料庫去重;在這個基礎爬蟲中,我使用了Python中的set這種記憶體去重方式,因為資料量比較少。 

# url管理器

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

    def has_new_url(self):
        '''
        判斷是否有未爬取的URL
        :return:
        '''
        return self.new_url_size() != 0

    def get_new_url(self):
        '''
        獲取一個未爬取的URL
        :return:
        '''
        new_url = self.new_urls.pop()
        self.old_urls.add(new_url)
        return new_url

    def add_new_url(self, url):
        '''
        將新的URL新增到未爬取的URL集合中
        :param url: 單個url
        :return:
        '''
        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):
        '''
        將新的URL新增到未爬取的URL集合中
        :param urls: urls:url集合
        :return:
        '''
        if urls is None or len(urls) == 0:
            return
        for url in urls:
            self.add_new_url(url)

    def new_url_size(self):
        '''
        獲取未爬取的URL集合的大小
        :return:
        '''
        return len(self.new_urls)

    def old_url_size(self):
        '''
        獲取已經爬取的URL集合的大小
        :return:
        '''
        return len(self.old_urls)

2.HTML下載器

HTML下載器用來下載網頁,這時候需要注意網頁的編碼,以保證下載的網頁沒有亂碼,下載器用了Requests模組,這個模組比urllib強大很多。

import requests
import chardet

class HtmlDownloader(object):
    def download(self, url):
        if url is None:
            return None

        user_agent = 'Mozilla/4.0 (compatible); MSIE 5.5; Windows NT'
        headers = {'User-Agent': user_agent}
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            response.encoding = chardet.detect(response.content)['encoding']
            return response.text
        else:
            print('網頁開啟失敗!')
        return None

3.HTML解析器
HTML解析器使用BeautifulSoup進行HTML解析。需要解析的部分主要分為提取相關詞條頁面的URL和提取當前詞條的標題和摘要資訊。

# coding:utf-8

import re
from bs4 import BeautifulSoup


class HtmlParser(object):
    def parser(self, page_url, html_cont):
        '''
        用於解析網頁內容,抽取URL和資料
        :param page_url: 下載頁面中的URL
        :param html_cont: 下載的網頁內容
        :return: 返回URL和資料
        '''
        if page_url is None or html_cont is None:
            return
        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)
        # print(new_urls, new_data)
        return new_urls, new_data

    def __get_new_urls(self, page_url, soup):
        '''
        抽取新的url集合
        :param page_url:下載頁面的url
        :param soup: soup
        :return: 返回新的url集合
        '''
        new_urls = set()
        # print('new_urls:', new_urls)
        # 抽取符合要求的a標記
        links = soup.find_all('a', href=re.compile(r'/item/[0-9a-zA-Z%]'))
        print(links)
        for link in links:
            # 提取href屬性
            new_url = link.get('href')
            # print('new_url:', new_url)
            # 拼接成完整網址
            new_full_url = 'http://baike.baidu.com' + new_url
            # print('new_full_url', new_full_url)
            new_urls.add(new_full_url)
        # print('new_urls:', new_urls)
        return new_urls

    def __get_new_data(self, page_url, soup):
        '''
        抽取有效資料
        :param page_url: 下載頁面的URL
        :param soup: soup
        :return: 返回有效資料
        '''
        data = {}
        data['url'] = page_url
        title = soup.find(name='dd', class_='lemmaWgt-lemmaTitle-title').find('h1')
        # print(title.text)
        data['title'] = title.text
        summary = soup.find(name='div', class_='lemma-summary')
        # print(summary.text)
        data['summary'] = summary.text

        return data

4.資料儲存器
資料儲存器主要包括兩個方法:store_data(data)用於將解析出來的資料儲存到記憶體中,output_html()用於將儲存的資料輸出為指定的檔案格式(自己定義)。 

import codecs

class DataOutput(object):
    def __init__(self):
        self.datas = []

    def store_data(self, data):
        if data is None:
            return
        self.datas.append(data)

    def output_html(self):
        fout = codecs.open('baike.html', 'a', encoding='utf-8')
        fout.write('<html>')
        fout.write('<head><meta charset="utf-8" /></head>')
        fout.write('<body>')
        fout.write('<table>')
        for data in self.datas:
            fout.write('<tr>')
            fout.write('<td>%s</td>'%data['url'])
            fout.write('<td>%s</td>'%data['title'])
            fout.write('<td>%s</td>'%data['summary'])
            fout.write('</tr>')
            self.datas.remove(data)
        fout.write('</table>')
        fout.write('</body>')
        fout.write('</html>')
        fout.close()

5.爬蟲排程器
爬蟲排程器用來協調管理這些模組。

# encoding:utf-8

from The_Basic_Spider.DataOutput import DataOutput
from The_Basic_Spider.HtmlDownloader import HtmlDownloader
from The_Basic_Spider.HtmlParser import HtmlParser
from The_Basic_Spider.URLManager import UrlManager


class SpiderMan(object):
    def __init__(self):
        self.manager = UrlManager()
        self.downloader = HtmlDownloader()
        self.parser = HtmlParser()
        self.output = DataOutput()

    def crawl(self, root_url):
        # 新增入口URL
        self.manager.add_new_url(root_url)
        # 判斷url管理器中是否有新的url,同時判斷抓取了多少個url
        while(self.manager.has_new_url() and self.manager.old_url_size() < 100):
            try:
                # 從URL管理器中獲取新的url
                new_url = self.manager.get_new_url()
                print(new_url)
                # HTML下載器下載網頁
                html = self.downloader.download(new_url)
                # HTML解析器抽取網頁資料
                new_urls, data = self.parser.parser(new_url, html)
                print(new_urls, data)
                # 將抽取的url新增到URL管理器中
                self.manager.add_new_urls(new_urls)
                # 資料儲存器儲存檔案
                self.output.store_data(data)
                print('已經抓取了%s個連結' % self.manager.old_url_size())
            except Exception:
                print('crawl failed')
            # 資料儲存器將檔案輸出成指定格式
            self.output.output_html()


if __name__ == '__main__':
    spider_man = SpiderMan()
    spider_man.crawl('http://baike.baidu.com/view/284853.htm')

然後就可以爬取100條百度百科詞條啦~爬去的資訊將儲存在baike.html裡。

6.爬取結果(baike.html)

當然,你也可以試著爬取自己想爬取的網路資料哦~

如果有幫助,點個喜歡吧~