美文网首页程序员
初识python及数据爬取

初识python及数据爬取

作者: e_payne | 来源:发表于2017-05-09 23:57 被阅读924次

    初识python

    作为一位前端开发人员,一直以来,接触最多的也都是html,css,js;有时候会需要搭建一些node服务器,写一些node后台代码,仅此而已;

    而python,只是在以前使用某些软件时,需要python环境,就安装到了电脑,然后,从来都没有真正的接触过它;

    随着数据分析、深度学习、机器学习的发展,也让我开始了python的学习之旅;虽然都说,不管是什么语言,基本上都是相通的;但是对于一种你从未接触过的语言,基础,还是非常重要的;所以,我还是默默的打开了浏览器,在百度中搜索了“python基础教程”,最后找到了Python 基础教程 | 菜鸟教程,在这里面,有环境的搭建、基本语法、数据类型、常用函数等非常基础的教程,我觉得非常适合我这种从来没有接触过的人;随后,我花了几个小时的时间,将这里面基础教程的所有内容看了一遍,在看的过程中,也跟着做了一些练习;

    虽然说,看了基础教程,也顶多你大概能够使用python进行一些简单的运算而已;而作为开发人员,都明白一个道理,最好、最快的学习一种语言的方式当然是从一个简单的项目开始,自己能够从头开始做一个自己觉得有意思但是难度不是很大的东西,这样,不仅能够让自己能够更快的去理解这种语言,而且,会使自己更有学习的动力和信心;因此,我开始了一个简单的网站的数据爬取的实现,因为对于我这种前端出生的人来说,与浏览器打交道,与网页打交道,相对来说,简单很多;

    开始

    首先,我肯定不知道从何处开始,因此,我只能继续百度“python 爬虫”;最后找到了这篇文章“Python爬虫实战二之爬取百度贴吧帖子”,为什么选择它呢?只有一个原因,在它的文章最后,有完整的代码,我没去看里面的描述,而是,直接用sublime直接创建了一个名为

    $ pachong.py
    

    的文件,然后将代码全部拷贝进去(虽然说可能代码根本运行不通);

    随后,我开始了我的爬虫之旅,一开始,我就直接在拷贝的代码基础上直接修改,而不同的是它爬取的是百度贴吧,我爬取的是汽车之家。然后代码就在这儿pachong.py(由于代码较多,就不直接贴出来了,有兴趣的,可以直接点链接进github查看);在这里面有个很坑的地方,它的所有筛选自己需要数据的方式是通过正则匹配的方式实现的,而我什么也不知道的跟着学着,也使用正则,让我为了从整个html中筛选自己需要的,花费了太多的时间,而且效果一般;但是后面才发现,已经有很完善的专门匹配页面内容方式的Python库BeautifulSoup(这是它的中文文档链接);

    使用BeautifulSoup重写

    当发现了BeautifulSoup之后,简单看了一篇BeautifulSoup教程,看完之后,如获至宝,因为它的使用方式里面有很多和前端里面去获取元素,获取节点有异曲同工之妙;而我最喜欢使用的,是里面的“CSS选择器”方式,简直和前端使用jquery一模一样,比如:

    通过标签名查找

    print soup.select('p')
    

    通过类名查找

    print soup.select('.sister')
    

    通过 id 名查找

    print soup.select('#link1')
    

    ......等等;

    因此,我果断选择使用BeautifulSoup对上面最初的版本进行重写,尤其是在对内容的筛选;而这一次,我选择了去爬取“蚂蜂窝”的游记;

    作为前端开发的我,对于Chrome DevTools的使用,简直是易如反掌;所以很容易就可以找出怎么去获取自己需要的内容(到底是用类名查找还是id查找,或者是什么组合查找),对于Chrome DevTools不是很熟的同学,可以看下这个感觉挺全的;

    以爬取蚂蜂窝的游记为例,比如这一篇

    1、通过request获取网页

    request = urllib2.Request('http://www.mafengwo.cn/i/6958115.html')
    response = urllib2.urlopen(request)
    soup = BeautifulSoup(response.read().decode('utf8').encode('utf8'), "html.parser")
    

    2、获取标题

    return soup.select('.headtext')[0].string
    

    3、获取文章html内容

    article = soup.select('.vc_article')[0]
    html = article.prettify()
    

    4、获取用户信息(如头像,名称),这个稍微要复杂一些,因为它在上面第一步直接请求的html页面里面是找不到的,然后通过Chrome DevTools中的Network功能,可以找到拉取这些信息的请求地址“https://www.mafengwo.cn/note/pagelet/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249”,细心的你可能会发现,在这个请求中有个“6958115”,这个不就是第一步里面页面的结尾数字吗,我们可以理解为id;那么,这个请求就是通过

    开始

    https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249](https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%22
    

    加上 id

    6958115
    

    加上结尾

    %22%7D&_=1492868086249
    

    最后组合成的一个完整的url,然后通过第一步请求后,将获取的数据通过正则的方式,只去html部分,然后通过BeautifulSoup取出对应的头像,姓名;

    //其中article_id就是上面说的第一步链接结尾数字“6958115”
    userInfoURL = 'https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%22' + article_id +'%22%7D&_=1492868086249'
    
    request = urllib2.Request(userInfoURL)
    response = urllib2.urlopen(request)
    result = response.read()
    
    pattern = re.compile('jQuery.*?\(')
    pattern1 = re.compile('\)\;')
    
    result = re.sub(pattern, "", result)
    result = re.sub(pattern1, "", result)
    
    result = eval(result)
    
    html = result['data']['html']
    
    soup = BeautifulSoup(html, "html.parser")
    
    //头像
    avatar = soup.select('.per_pic img')[0]['src']
    
    //用户名
    name = soup.select('.per_name')[0]['title'].encode('utf-8')
    
    

    搭建服务器

    在你爬取到数据之后,你总会希望能够在界面上能够真正的展示出来,所以,我就决定使用python搭建一个简单的本地服务器;因为通过学习python的时候发现菜鸟教程确实比较适合我这种菜鸟的,所以就看完了Django 菜鸟教程,这个教程虽然简单,但是全面,对我做一个简单服务器来说,足够了;然后,就通过这个教程搭建了一个简单的python服务器,在浏览器中,就可以看到自己爬取的页面了,具体可见整个项目代码

    mongodb 数据保存、使用

    在你爬取一篇过后,肯定是不会停止的,所以,我们总会找个能够保持我们爬取数据的地方(数据库);因为以前在进行node开发的时候,使用过mongodb,所以就选择了它作为我保存数据的地方;使用python来操作mongodb,我没有找到相关比较好的文章,所以就直接参考的PyMongo 3.4.0 documentation这个api文档,这个夜比较详细和简单,对于我来说够用了;它包含了如何和mongodb链接、如何获取数据库,如何获取数据库里面的collection,如何查找、添加数据等等;其实很简单:

    from pymongo import MongoClient
    import settings
    
    #连接mongodb
    client=MongoClient('mongodb://127.0.0.1:27017/')
    
    //获取数据库
    db = client[settings.DBNAME]
    
    // 获取数据库里面的collection
    def getCollection(collection):
        if(collection):
            return db[collection]
        else:
            return None 
    

    数据保存的代码就不贴出来了,有兴趣可以看这个models.py.

    自动爬取所有游记

    当你想爬取更多的时候,你肯定不希望是自己手动去查找一个一个的id,然后手动爬取,所以,我们就希望有更加自动化的爬取方式;对于这种方式,必须得解决下面两个问题:

    • 获取所有的游记id(就形如“6958115”这种的东西)
    • 解决因为自动化请求过快,过于频繁,导致“服务器拒绝访问”的问题

    第一个,获取所有id;当你使用Chrome DevTools Network去看列表下一页的请求的时候,你会发现,它访问了一个“http://www.mafengwo.cn/note/pagelet/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522&params=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A1%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862”这样的链接,它也是和上面获取用户信息一样分成三个部分,其中有个第几页的参数“page=1”,这里面就返回了所有的列表的html代码,其中包括我们需要的id;

    url = 'http://www.mafengwo.cn/note/__pagelet__/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522&params=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A'+str(page)+'%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862'
    
    request = urllib2.Request(url)
    response = urllib2.urlopen(request)
    result = response.read()
    
    pattern = re.compile('jQuery.*?\(')
    pattern1 = re.compile('\)\;')
    
    result = re.sub(pattern, "", result)
    result = re.sub(pattern1, "", result)
    result = eval(result)
    
    html = result['data']['html']
    html = html.replace('\\/', '/')
    html = html.decode('string-escape')
    soup = BeautifulSoup(html, "html.parser")
    
    links = soup.select('.tn-item .tn-image a')
    _ids = []
    
    for link in links:
        _id = link['href'].replace('/i/', '').replace('.html', '')
        _ids.append(_id)
    
    

    然后我们就会根据每一页获取的id循环自动跑爬取对应页面数据并保存至数据库,每跑完一页的数据,就会递归跑下一页数据,直到最后一页

    只是在跑的过程中,就会遇到第二个问题,因为访问过快、过于频繁而导致服务器拒绝访问,在这儿我没有通过网上说的各种高端的方式,而是采用的比较笨重的方式,就是在跑完一个请求后,让程序休息几秒钟,再去进行下一个请求,我将时间设置的10秒,目前没有拒绝访问的问题,只是跑起来比较慢一些;

    import time
    
    .....
    time.sleep(10)
    .....
    
    

    对于上面的所有代码,如果感兴趣的,整个项目代码可以在这儿(github)找到.

    目前,爬取就差不多只有这些,后面会慢慢继续去完善和学习;对于我来说,python的学习之路也才刚刚开始;

    相关文章

      网友评论

        本文标题:初识python及数据爬取

        本文链接:https://www.haomeiwen.com/subject/difwtxtx.html