python网络爬虫——数据抓取

我们需要让爬虫从每个网页中抽取一些数据,然后实现某些事情,这种做法被称为抓取
分析网页
查看网页源代码,使用Firebug Lite扩展,Firebug是Joe Hewitt开发的一套与Firefox集成在一起的功能强大的web开发工具,可以实时编辑、调试和监测任何页面的CSS、HTML和JavaScript。在这里用于网页源代码的查看。
安装Firebug Lite,下载Firebug Lite的包,然后再浏览器中安装这个插件。

三种网页抓取的方法

正则表达式、BeatifulSoup模板、强大的lxml模块
正则表达式

爬取第一页所有国家的国土面积

def download(url,user_agent='wswp',proxy=None,num_retries=2):
    print 'Downloading:',url
    headers={'User-agent':user_agent}
    request=urllib2.Request(url,headers=headers)

    opener=urllib2.build_opener()
    if opener:
        proxy_params={urlparse.urlparse(url).scheme:proxy}
        opener.add_handler(urllib2.ProxyHandler(proxy_params))

    try:
        html=urllib2.urlopen(request).read()
    except urllib2.URLError as e:
        print 'Download:' ,e.reason
        html=None
        if num_retries>0:
            if hasattr(e,'code') and 500 <=e.code<600:
                return download(url,num_retries-1)

    return html

def get_links(html):
    webpage_regx=re.compile('<a[^>]+href=["\'](.*?)["\']',re.IGNORECASE)
    # webpage_regx=re.compile(,re.IGNORECASE)
    link_list1=webpage_regx.findall(html)
    link_list2=[]
    for link in link_list1:
        if re.search('/view/',link):
            link_list2.append(link)
    return link_list2

import re

url='http://example.webscraping.com/view/United-Kingdom-239'
html=download(url)

for link in get_links(html):
    link = urlparse.urljoin(url, link)
    areas=download(link)
    # print areas
    #匹配国家面积
    context=re.findall(r'<td class="w2p_fw">(.*?)</td>',areas)[1]
    print context

运行结果:
这里写图片描述
正则表达式提供了抓取数据的快捷方式,但是该方法过于脆弱,容易在网页更新后出现问题。
Beautful Soup
Beautful Soup是一个非常流行的Python模块。该模块可以解析网页,并提供定位内容的便捷接口。
安装

 pip install beautifulsoup4 --user

使用第一步:将已经下载的HTML内容解析为soup文档。
使用find或者find_all方法获取.
Lxml
基于libxml2这一XML解析库的Python封装.该模块使用C编写,解析速度更快.
第一步:将有可能步合法的HTML解析为统一格式.

import lxml.html

broken_html='<ul class=country><li>Area<li>Population</ul>'
tree=lxml.html.fromstring(broken_html)
fixed_html=lxml.html.tostring(tree,pretty_print=True)

print fixed_html

"""
<ul class="country">
<li>Area</li>
<li>Population</li>
</ul>
"""

测试三种方法的性能

import re
import urllib2
import urlparse
from bs4 import BeautifulSoup
import lxml.html
import time

#
#
#
#获取网页内容
def download(url,user_agent='wswp',proxy=None,num_retries=2):
    print 'Downloading:',url
    headers={'User-agent':user_agent}
    request=urllib2.Request(url,headers=headers)

    opener=urllib2.build_opener()
    if opener:
        proxy_params={urlparse.urlparse(url).scheme:proxy}
        opener.add_handler(urllib2.ProxyHandler(proxy_params))

    try:
        html=urllib2.urlopen(request).read()
    except urllib2.URLError as e:
        print 'Download:' ,e.reason
        html=None
        if num_retries>0:
            if hasattr(e,'code') and 500 <=e.code<600:
                return download(url,num_retries-1)

    return html

#使用正则表达式匹配
def re_scraper(html):
    results={}
    results['area']=re.search('<tr id="places_area__row">.*?<td class="w2p_fw">(.*?)</td>',html).groups()[0]
    return results


#使用BeautifulSoup匹配
def bs_scraper(html):
    soup=BeautifulSoup(html)
    results={}
    results['area']=soup.find('table').find('tr',id='places_area__row').find('td', class_='w2p_fw').string

    return results

#使用cssselect选择器匹配
def lxml_scraper(html):
    tree=lxml.html.fromstring(html)
    results={}
    conf=tree.cssselect('table > tr#places_area__row > td.w2p_fw')[0].text_content()
    results['area']=conf

    return results



#计算获取时间
#每个网站爬取的次数
NUM_ITERATIONS=1000
html=download('http://example.webscraping.com/places/default/view/Afghanistan-1')
for name,scraper in [('Re',re_scraper),('Bs',bs_scraper),('Lxml',lxml_scraper)]:

    #开始的时间
    start=time.time()
    for i in range(NUM_ITERATIONS):
        if scraper==re_scraper:
#默认情况下,正则表达式模块会缓存搜索结果,为了使对比条件更一致,re.purge()方法清除缓存
            re.purge()
        result=scraper(html)
        #检查结果
        assert(result['area']=='647,500 square kilometres')

    #结束时间
    end=time.time()

    print '%s: %.2f seconds' %(name,end-start)


这里写图片描述
结果分析:
由于lxml和正则表达式都是用C语言写的,所以效果比用Python写的BeautifulSoup要好.由于lxml在搜索之前必须输入解析为内部格式,所以会产生额外的开销.而爬取同一网页时这种开销会降低.
方法总结

抓取方法 性能 使用难度 安装难度
正则表达式 困难 简单(内置)
Beautiful Soup 简单 简单(纯python)
Lxml 简单 相对困难

如果是下在网页,而不是抽取数据的话,那么使用Beautiful Soup,如果只需抓取少量数据,并且避免额外依赖的话,选择正,通常情况下使用lxml比较合适.

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页