欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python网络爬虫——数据抓取

程序员文章站 2022-07-04 08:09:40
...

我们需要让爬虫从每个网页中抽取一些数据,然后实现某些事情,这种做法被称为抓取
分析网页
查看网页源代码,使用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

运行结果:
python网络爬虫——数据抓取
正则表达式提供了抓取数据的快捷方式,但是该方法过于脆弱,容易在网页更新后出现问题。
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)


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

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

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