python簡單爬蟲(二)

weixin_33912246發表於2018-04-18

  

  上一篇簡單的實現了獲取url返回的內容,在這一篇就要第返回的內容進行提取,並將結果儲存到html中。

 

一 、 需求:

 

  抓取主頁面:百度百科Python詞條   https://baike.baidu.com/item/Python/407313

 

  

分析上面的原始碼格式,便於提取:

  • 關鍵詞分析:位於class為lemmaWgt-lemmaTitle-title的dd元素的第一個h1標籤內

 

  •  簡介分析(位於class為lemma-summary的div的text內容)

 

   

  • 其他相關聯的標籤的分析(是a標籤,且href以/item/開頭)

 

 

 

 

二、抓取過程流程圖:

 

 

 

 

 三、分析:

1. 網頁下載器:

1.作用:

將網際網路上URL對應的網頁以HTML形式下載到本地

常用的本地下載器
  1、urllib2 Python官方基礎模組
  2、requests 第三方包,功能更強大

 2.urllib下載網頁的三種方法

 (1)URL傳入urllib2.urlopen(url)方法

import urllib2
#直接請求
response = urllib2.urlopen('http://www.baidu.com')

#獲取狀態碼,如果是200表示成功
code = response.getcode()

#讀取內容
cont = response.read()

 

 (2)新增data、http header

將url、data、header傳入urllib.Request方法
然後 URLlib.urlopen(request)

import urllib2

#建立Request物件
request = urllin2.Request(url)

#新增資料
request.add_data('a'.'1')

#新增http的header 將爬蟲程式偽裝成Mozilla瀏覽器
request.add_header('User-Agent','Mozilla/5.0')

#傳送請求獲取結果
response = urllib2.urlopen(request)

 

 (3)新增特殊情景的處理器

處理使用者登入才能訪問的情況,新增Cookie
或者需要代理才能訪問 使用ProxyHandler
或者需要使用https請求

 

2.網頁解析器

 1.作用:

從網頁中提取有價值資料的工具

以HTML網頁字串為輸入資訊,輸出有價值的資料和新的待爬取url列表

網頁解析器種類
  1、正規表示式 將下載好的HTML字串用正規表示式匹配解析,適用於簡單的網頁解析 字串形式的模糊匹配
  2、html.parser python自帶模組
  3、BeautifulSoup 第三方外掛
  4、xml 第三方外掛

 

原理是解析成DOM樹:

 

 

 

 

 2.BeautifulSoup簡介及使用方法:

 1.簡介:

  BeautifulSoup:Python第三方庫,用於從HTML或XML中提取資料

 

安裝並測試beautifulsoup

方法1:-安裝:pip install beautifulsoup4
    -測試:import bs4

方法2:pycharm--File--settings--Project Interpreter--新增beautifulsoup4

 

 2.語法介紹:

根據HTML網頁字串可以建立BeautifulSoup物件,建立好之後已經載入完DOM樹
即可進行節點搜尋:find_all、find。搜尋出所有/第一個滿足要求的節點(可按照節點名稱、屬性、文字進行搜尋)
得到節點之後可以訪問節點名稱、屬性、文字

如:
<a href="123.html" class="aaa">Python</a>
可根據:
節點名稱:a
節點屬性:href="123.html" class="aaa"
節點內容:Python

 

建立BeautifulSoup物件:

from bs4 import BeautifulSoup

#根據下載好的HTML網頁字串建立BeautifulSoup物件
soup = BeautifulSoup(
  html_doc, #HTML文件字串
  'html.parser' #HTML解析器
  from_encoding='utf-8' #HTML文件編碼
)

 

搜尋節點:
方法:find_all(name,attrs,string)

#查詢所有標籤為a的節點
  soup.find_all('a')

#查詢所有標籤為a,連結符合/view/123.html形式的節點
  soup.find_all('a',href='/view/123.html')
  soup.find('a',href=re.compile('aaa')) #用正規表示式匹配內容

#查詢所有標籤為div,class為abc,文字為Python的節點
  soup.find_all('div',class_='abc',string='Python') #class是Python關鍵字 避免衝突

 由於class是python的關鍵字,所以講class屬性加了個下劃線。


訪問節點資訊:
  得到節點:<a href="123.html" class="aaa">Python</a>

#獲取查詢到的節點的標籤名稱
  node.name
#獲取查詢到的節點的href屬性
  node['href']
#獲取查詢到的節點的連線文字
  node.gettext()

 

四、程式碼實現:

spider.py
# 爬蟲的入口排程器
from baike import url_manager, html_downloader, html_parser, html_outputer


class SpiderMain(object):
    def __init__(self):
        self.urlManager = url_manager.UrlManager()
        self.downloader = html_downloader.HtmlDownLoader()
        self.parser = html_parser.HtmpParser()
        self.outputer = html_outputer.HtmlOutpter()


    def craw(self,url):
        count = 1 #定義爬取幾個頁面
        self.urlManager.add_new_url(url)
        while self.urlManager.has_new_url():
            try:
                # 獲取一個url
                new_url = self.urlManager.get_new_url()
                # 訪問url,獲取網站返回資料
                html_content = self.downloader.download(new_url)
                new_urls, new_datas = self.parser.parse(new_url, html_content)
                self.urlManager.add_new_urls(new_urls)
                self.outputer.collect_data(new_datas)
                print(count)
                if count == 5:
                    break
                count = count+1
            except Exception as e:
                print("發生錯誤",e)
        # 將爬取結果輸出到html
        self.outputer.out_html()

if __name__=="__main__":
    url = 'https://baike.baidu.com/item/Python/407313'
    sm = SpiderMain()
    sm.craw(url)

 

 

 

url_manager.py
# url管理器
class UrlManager(object):
    def __init__(self):
        # 定義兩個set,一個存放未爬取的url,一個爬取已經訪問過的url
        self.new_urls = set()
        self.old_urls = set()

    # 新增一個url的方法
    def add_new_url(self,url):
        if url is None:
            return  None
        if url not in self.new_urls and url not in self.old_urls:
            self.new_urls.add(url)

    # 判斷是否還有待爬取的url(根據new_urls的長度判斷是否有待爬取的頁面)
    def has_new_url(self):
        return len(self.new_urls) != 0

    # 定義獲取一個新的url的方法
    def get_new_url(self):
        if len(self.new_urls)>0:
            # 從new_urls彈出一個並新增到old_urls中
            new_url = self.new_urls.pop()
            self.old_urls.add(new_url)
            return new_url

    # 批量新增url的方法
    def add_new_urls(self, new_urls):
        if new_urls is None:
            return
        for url in new_urls:
            self.add_new_url(url)

 

 

html_downloader.py
# 讀取網頁的類
import urllib.request


class HtmlDownLoader(object):
    def download(self, url):
        if url is None:
            return
        # 訪問url
        response = urllib.request.urlopen(url)
        # 如果返回的狀態碼不是200代表異常
        if response.getcode() != 200:
            return
        return response.read()

 

 

 

html_parser.py
# 網頁解析器類
import re
import urllib

from bs4 import BeautifulSoup


class HtmpParser(object):
    # 解析讀取到的網頁的方法
    def parse(self, new_url, html_content):
        if html_content is None:
            return
        soup = BeautifulSoup(html_content,'html.parser',from_encoding='utf-8')
        new_urls = self.get_new_urls(new_url,soup)
        new_datas = self.get_new_datas(new_url,soup)
        return new_urls, new_datas


    # 獲取new_urls的方法
    def get_new_urls(self, new_url, soup):
        new_urls = set()
        # 查詢網頁的a標籤,而且href包含/item
        links = soup.find_all('a',href=re.compile(r'/item'))
        for link in links:
            # 獲取到a必去哦啊Ian的href屬性
            url = link['href']
            # 合併url。使爬到的路徑變為全路徑,http://....的格式
            new_full_url = urllib.parse.urljoin(new_url,url)
            new_urls.add(new_full_url)
        return new_urls



    # 獲取new_data的方法
    def get_new_datas(self, new_url, soup):
        new_datas = {}
        # 獲取標題內容
        title_node = soup.find('dd',class_='lemmaWgt-lemmaTitle-title').find('h1')
        new_datas['title'] = title_node.get_text()

        #獲取簡介內容
        summary_node = soup.find('div',class_='lemma-summary')
        new_datas['summary'] = summary_node.get_text()

        new_datas['url'] = new_url

        return new_datas

 

 

 

html_outputer.py
# 爬蟲的入口排程器
from baike import url_manager, html_downloader, html_parser, html_outputer


class SpiderMain(object):
    def __init__(self):
        self.urlManager = url_manager.UrlManager()
        self.downloader = html_downloader.HtmlDownLoader()
        self.parser = html_parser.HtmpParser()
        self.outputer = html_outputer.HtmlOutpter()


    def craw(self,url):
        count = 1 #定義爬取幾個頁面
        self.urlManager.add_new_url(url)
        while self.urlManager.has_new_url():
            try:
                # 獲取一個url
                new_url = self.urlManager.get_new_url()
                # 訪問url,獲取網站返回資料
                html_content = self.downloader.download(new_url)
                new_urls, new_datas = self.parser.parse(new_url, html_content)
                self.urlManager.add_new_urls(new_urls)
                self.outputer.collect_data(new_datas)
                print(count)
                if count == 5:
                    break
                count = count+1
            except Exception as e:
                print("發生錯誤",e)
        # 將爬取結果輸出到html
        self.outputer.out_html()

if __name__=="__main__":
    url = 'https://baike.baidu.com/item/Python/407313'
    sm = SpiderMain()
    sm.craw(url)

 

 

 

 

執行spider.py的主函式:(結果會將提取到的結果儲存到html中)

 

 

 

 總結:

  python的類類似於java,繼承object

  python的返回值return和return None一樣(None類似於java的null關鍵字)

 

 

下面附上自己基於java實現此爬蟲的地址:

 

相關文章