(轉)Python中第三方模塊的使用心得

3.4. Python中第三方模塊的使用心得
上一頁  第 3 章 python學習心得和體會  下一頁

3.4. Python中第三方模塊的使用心得

前面已經說了,其實學習Python的過程,不少時候就是在學習如何使用第三方模塊,完成本身須要的功能。 html

3.4.1. 去哪找python的第三方類庫

關於Python的第三方庫類庫,其實網上不少不少相關資料。 html5

其中,官網的Python庫:Python Package Index,其中有N多N多的庫,有須要的人,能夠去那裏找找。 python

其餘的網上的N多資源中,我以爲值得看看的有: web

  1. http://www.elias.cn/Python/HomePage中的3.3 用第三方類庫的部分。

下面就來總結一下,我的對於一些第三方模塊的使用心得。 正則表達式

3.4.2. BeautifulSoup

3.4.2.1. BeautifulSoup模塊簡介

Python的BeautifulSoup模塊,能夠幫助你實現HTML和XML的解析 網頁爬蟲

先說一下,通常寫網頁爬蟲,即抓取網頁的html源碼等內容,而後分析,提取相應的內容。 瀏覽器

這種分析html內容的工做,若是隻是用普通的正則表達式re模塊去一點點匹配的話,對於內容簡單點的網頁分析,仍是基本夠用。 app

可是對於工做量很大,要分析的內容很繁雜的html,那麼用re模塊,就會發現沒法實現,或很難實現。 wordpress

而使用beautifulsoup模塊去幫你實現分析html源碼的工做的話,你就會發現,事情變得如此簡單,極大地提升了分析html源碼的效率。 函數

好比我這裏的想要實現博客搬家以前,想要抓取對應的博客中的內容,就須要先去打開一個URL地址,去解析其中的內容,找到第一個固定連接,而後一點點分析HTML中的內容,抓去下來,導出wordpress所須要的xml文件等。

這其中對於HTML的分析,就能夠利用BeautifulSoup這個模塊了。

更多內容參見"Beautiful Soup 中文文檔"

其中,原先連接:

http://www.crummy.com/software/BeautifulSoup/documentation.zh.html

已失效,最新的可用的地址是:

http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html

想要下載的話,這是BeautifulSoup的官網,其中能夠下載到最新的版本:

http://www.crummy.com/software/BeautifulSoup/

下面就介紹一些Beautifulsoup使用過程當中的心得和注意事項:

3.4.2.2. BeautifulSoup有時候會遇到非法的,不支持的html源碼而致使沒法解析或沒法正常解析html

在使用Beautifulsoup過程當中,對於大多數html源碼,經過指定正確的編碼,或者自己是默認UTF-8編碼而無需指定編碼類型,其均可以正確解析html源碼,獲得對應的soup變量。

而後就接着去利用soup實現你所想要的功能了。

可是有時候會發現,有些html解析後,有些標籤等內容丟失了,即所獲得的soup不是所指望的完整的html的內容。

這時候,極可能遇到了非法的html,即其中可能包含了一些不合法的html標籤等內容,致使Beautifulsoup雖然能夠解析,沒有報錯,可是實際上獲得的soup變量,內容缺失了一部分了。

好比我就遇到過很多這樣的例子:

  1. 部分Blogbus的帖子的html中非html5和html5的代碼混合致使Beautifulsoup解析錯誤

    以前在爲BlogsToWordPress添加Blogbus支持過程當中去解析Blogbus的帖子的時候,遇到一個特殊的帖子:http://ronghuihou.blogbus.com/logs/89099700.html,其中一堆的非html5的代碼中,包含了這樣一段html5的代碼的寫法,即標籤屬性值不加括號的:

    <SCRIPT language=JavaScript> 
    document.oncontextmenu=new Function("event.returnValue=false;"); //禁止右鍵功能,單擊右鍵將無任何反應 
    document.onselectstart=new Function( "event.returnValue=false;"); //禁止先擇,也就是沒法複製 
    </SCRIPT language=JavaScript>

    結果致使Beautifulsoup解析錯誤,獲得的soup中,找不到所須要的各類class等屬性值。

    對應的解決辦法就是,把這部分的代碼刪除掉,而後再解析就能夠了:

    其中一堆的非html5的代碼中,包含了這樣一段html5的代碼的寫法,即標籤屬性值不加括號的:

    foundInvliadScript = re.search("<SCRIPT language=JavaScript>.+</SCRIPT language=JavaScript>", html, re.I | re.S );
    logging.debug("foundInvliadScript=%s", foundInvliadScript);
    if(foundInvliadScript):
        invalidScriptStr = foundInvliadScript.group(0);
        logging.debug("invalidScriptStr=%s", invalidScriptStr);
        html = html.replace(invalidScriptStr, "");
        logging.debug("filter out invalid script OK");
    
    soup = htmlToSoup(html);
  2. 判斷瀏覽器版本的相關代碼,致使Beautifulsoup解析不正常

    以前在給BlogsToWordpress添加新浪博客的支持的過程當中

    遇到不少新浪博客的帖子的html中,包含不少判斷瀏覽器版本的相關代碼:

    <!–[if lte IE 6]>
    xxx
    xxx
    <![endif]–>

    由此致使Beautifulsoup解析html不正常。

  3. font標籤嵌套層次太多,致使Beautifulsoup沒法解析html

    接上面那個解析新浪博客帖子的例子,期間又遇到另一個問題,對於一些特殊帖子:http://blog.sina.com.cn/s/blog_5058502a01017j3j.html

    其包含特殊的好幾十個font標籤且是一個個嵌套的代碼,致使沒法Beautifulsoup沒法解析html,後來把對應嵌套的font標籤刪除掉,才能夠正常解析。

    相關python代碼爲:

    # handle special case for http://blog.sina.com.cn/s/blog_5058502a01017j3j.html
    processedHtml = processedHtml.replace('<font COLOR="#6D4F19"><font COLOR="#7AAF5A"><font COLOR="#7AAF5A"><font COLOR="#6D4F19"><font COLOR="#7AAF5A"><font COLOR="#7AAF5A">', "");
    processedHtml = processedHtml.replace("</FONT></FONT></FONT></FONT></FONT></FONT>", "");

遇到其餘相似的問題,也能夠去刪除或替換出錯代碼,便可解決問題。

不過須要說明的是,不少時候,你未必很容易就找到出錯的代碼。

想要找到出錯的代碼,更多的時候,須要你一點點調試,一點點的刪除看似可疑的一些html源碼,而後最終才能定位到出錯的代碼,而後刪除掉後,才能夠正常工做的。

3.4.2.3. BeautifulSoup的Tag的屬性

BeautifulSoup處理這種html源碼:

<a href="http://creativecommons.org/licenses/by/3.0/deed.zh" target="_blank">版權聲明</a>

後,是能夠經過

soup.a['href']

去得到對應的href屬性值的。

可是,想要去得到當前的某個未知的BeautifulSoup.Tag中,一共存在多少個屬性,以及每一個屬性的值的時候,殊不知道如何下手了。

好比對於以下html源碼:

<p class="cc-lisence" style="line-height:180%;">......</p>

想要得知,一共有兩個屬性,分別是class和style,而後就能夠經過上面的方法,去得到對應的屬性值了。

對此問題,雖然看到了官網的解釋:Tags的屬性中的你能夠將Tag當作字典來訪問標籤的屬性

可是仍是沒法經過:

if("class" in soup)

的方式去判斷soup中是否存在class屬性,由於此時soup是Beautifulsoup.Tag類型變量,而不是dict變量。

而且,若是去強制將soup轉換成爲dict變量:

soupDict = dict(soup)

會報錯的。

最後,仍是無心間發現,原來Beautifulsoup.Tag是有個attrs屬性的,其能夠得到對應的元組列表,每個元組是對應屬性名和屬性值:

attrsList = soup.attrs;
print "attrsList=",attrsList;
attrsList= [(u'class', u'cc-lisence'), (u'style', u'line-height:180%;')]

這樣,就能夠從元組列表中,本身去轉換,得到屬性的列表或字典變量了,就能夠接着按照本身意願去處理了。

[提示] 提示

另外,此處也經過

soup.name

得到了該tag的名字

而想要得到整個soup變量全部的屬性和方法的話,能夠用經典的dir去打印出來:

print "dir(soup)=",dir(soup);

此處的打印輸出爲:

dir(soup)= ['BARE_AMPERSAND_OR_BRACKET', 'XML_ENTITIES_TO_SPECIAL_CHARS', 'XML_SPECIAL_CHARS_TO_ENTITIES', '__call__', '__contains__', '__delitem__', '__doc__', '__eq__', '__getattr__', '__getitem__', '__init__', '__iter__', '__len__', '__module__', '__ne__', '__nonzero__', '__repr__', '__setitem__', '__str__', '__unicode__', '_convertEntities', '_findAll', '_findOne', '_getAttrMap', '_invert', '_lastRecursiveChild', '_sub_entity', 'append', 'attrMap', 'attrs', 'childGenerator', 'containsSubstitutions', 'contents', 'convertHTMLEntities', 'convertXMLEntities', 'decompose', 'escapeUnrecognizedEntities', 'extract', 'fetch', 'fetchNextSiblings', 'fetchParents', 'fetchPrevious', 'fetchPreviousSiblings', 'fetchText', 'find', 'findAll', 'findAllNext', 'findAllPrevious', 'findChild', 'findChildren', 'findNext', 'findNextSibling', 'findNextSiblings', 'findParent', 'findParents', 'findPrevious', 'findPreviousSibling', 'findPreviousSiblings', 'first', 'firstText', 'get', 'has_key', 'hidden', 'insert', 'isSelfClosing', 'name', 'next', 'nextGenerator', 'nextSibling', 'nextSiblingGenerator', 'parent', 'parentGenerator', 'parserClass', 'prettify', 'previous', 'previousGenerator', 'previousSibling', 'previousSiblingGenerator', 'recursiveChildGenerator', 'renderContents', 'replaceWith', 'setup', 'substituteEncoding', 'toEncoding']

有須要的話,能夠對這些屬性和方法,都嘗試一下,以便更加清楚其含義。

剛寫完上面這句話呢,而後本身隨便測試了一下attrMap:

attrMap = soup.attrMap;
print "attrMap=",attrMap;

而後就很驚喜的發現,原來此處的attrMap,就是我程序中所須要的屬性的dict變量啊:

attrMap= {u'style': u'line-height:180%;', u'class': u'cc-lisence'}

這樣,就又省去了我程序中將attrs轉換爲dict變量的操做了,更加提升了效率。在次感謝Beautifulsoup的開發者。

3.4.2.4. BeautifulSoup中使用find,findAll等函數時,除了字符串外,也能夠用正則表達式做爲參數

在使用Beautifulsoup的find/finaAll等函數時候,常見用法都是傳遞字符串自己,好比:

foundIncontentTitle = lastItem.find(attrs={"class":"a-incontent a-title"});

能夠找到:

<a href="/serial_story/item/7d86d17b537d643c70442326" class="a-incontent a-title" target=_blank>I/O-Programming_HOWTO(上)zz</a>

中的值。

可是卻沒法匹配:

<a href="/serial_story/item/0c450a1440b768088fbde426" class="a-incontent a-title cs-contentblock-hoverlink" target="_blank">爲何幸運的人總幸運倒黴的人老倒黴-1   斯賓塞·約翰遜著</a>

即,class的值是:a-incontent a-title cs-contentblock-hoverlink,而不只僅是a-incontent a-title

此時,若是想要匹配才class,使用傳統的方法,則須要寫兩個find去匹配,然後來得知,原來find/findAll等函數的參數中,也可使用正則表達式的,因此就用了:

titleP = re.compile("a-incontent a-title(\s+?\w+)?");# also match a-incontent a-title cs-contentblock-hoverlink
foundIncontentTitle = lastItem.find(attrs={"class":titleP});

就能夠一次性匹配,a-incontent a-title,a-incontent a-title cs-contentblock-hoverlink,以及將來更多可能的a-incontent a-title xxx了。

感嘆一句,Beautifulsoup,作的的確很好用,特此感謝做者。

上一頁  上一級  下一頁
3.3. Python中自帶模塊的使用心得  起始頁

 第 4 章 crifan的Python庫:crifanLib.py


特別感謝Crifan Li對python及幾個第三方庫的總結,這裏提供做者的網站,但願給更多的人提供幫助:http://www.crifan.com/files/doc/docbook/python_summary/release/htmls/index.html

相關文章
相關標籤/搜索