Django+python+BeautifulSoup組合的垂直搜尋爬蟲

來源:互聯網
上載者:User

使用python+BeautifulSoup完成爬蟲抓取特定資料的工作,並使用Django搭建一個管理平台,用來協調抓取工作。

因為自己很喜歡Django admin後台,所以這次用這個後台對抓取到的連結進行管理,使我的爬蟲可以應對各種後期的需求。比如分時段抓取,週期性對已經抓取的地址重新抓取。資料庫是用python內建的sqlite3,所以很方便。

 

這幾天正好在做一個電影推薦系統,需要些電影資料。本文的例子是對豆瓣電影抓取特定的資料。

 

第一步:建立Django模型


模仿nutch的爬蟲思路,這裡簡化了。每次抓取任務開始先從資料庫裡找到未儲存的(is_save = False)的連結,放到抓取鏈表裡。你也可以根據自己的需求去過濾連結。

 

python代碼:

class Crawl_URL(models.Model):<br /> url = models.URLField('抓取地址',max_length=100, unique=True)<br /> weight = models.SmallIntegerField('抓取深度',default = 0)#抓取深度起始1<br /> is_save = models.BooleanField('是否已儲存',default= False)#<br /> date = models.DateTimeField('儲存時間',auto_now_add=True,blank=True,null=True)<br /> def __unicode__(self):<br /> return self.url 

然後產生相應的表。

 

還需要一個admin管理後台

class Crawl_URLAdmin(admin.ModelAdmin):<br /> list_display = ('url','weight','is_save','date',)<br /> ordering = ('-id',)<br /> list_filter = ('is_save','weight','date',)<br /> fields = ('url','weight','is_save',)<br />admin.site.register(Crawl_URL, Crawl_URLAdmin) 

 

 

 

第二步,編寫爬蟲代碼

 

爬蟲是單線程,並且每次抓取後都有相應的暫訂,豆瓣網會禁止一定強度抓取的爬蟲

爬蟲根據深度來控制,每次都是先產生連結,然後抓取,並解析出更多的連結,最後將抓取過的連結is_save=true,並把新連結存入資料庫中。每次一個深度抓取完後都需要花比較長的時候把連結匯入資料庫。因為需要判斷連結是否已存入資料庫。

 

這個只對滿足Regex http://movie.douban.com/subject/(/d+)/ 的地址進行資料解析。並且直接忽略掉不是電影模組的連結。

第一次抓取需要在後台加個連結,比如http://movie.douban.com/chart,這是個熱門排行榜的頁面,電影比較受歡迎。

 

python代碼:

#這段代碼不能格式化發

# coding=UTF-8

import urllib2

from BeautifulSoup import *

from urlparse import urljoin

from pysqlite2 import dbapi2 as sqlite

from movie.models import *

from django.contrib.auth.models import User

from time import sleep

 

image_path = 'C:/Users/soul/djcodetest/picture/'

 

user = User.objects.get(id=1)

def crawl(depth=10):

    for i in range(1,depth):

        print '開始抓取 for %d....'%i

        pages = Crawl_URL.objects.filter(is_save=False)

        newurls={}      

        for crawl_page in pages:

            page = crawl_page.url

            try:

                c=urllib2.urlopen(page)

            except:

                continue     

            try:

                #解析中繼資料和url

                soup=BeautifulSoup(c.read())

                #解析電影頁面

                if re.search(r'^http://movie.douban.com/subject/(/d+)/$',page):

                    read_html(soup)

                #解析出有效連結,放入newurls

                links=soup('a')

                for link in links:      

                    if 'href' in dict(link.attrs):      

                        url=urljoin(page,link['href'])             

                    if url.find("'")!=-1: continue

                    if len(url) > 60: continue

                    url=url.split('#')[0]  # removie location portion

                    if re.search(r'^http://movie.douban.com', url):

                        newurls[url]= crawl_page.weight + 1 #串連有效。存入字典中

                        try:

                            print 'add url :'

                        except:

                            pass        

            except Exception.args:

                try:

                    print "Could not parse : %s" % args

                except:

                    pass

            #newurls存入資料庫 is_save=False weight=i

            crawl_page.is_save = True

            crawl_page.save()

            #休眠2.5秒

            sleep(2.5)

        save_url(newurls)          

#儲存url,放到資料庫裡

def save_url(newurls):

    for (url,weight) in newurls.items():

        url = Crawl_URL(url=url,weight=weight)

        try:

            url.save()

        except:

            try:

                print 'url重複:'

            except:

                pass

    return True


 



 

第三步,用BeautifulSoup解析頁面

抽取齣電影標題,圖片,劇情介紹,主演,標籤,地區。關於BeautifulSoup的使用可以看這裡BeautifulSoup技術文檔

 

#抓取資料<br />def read_html(soup):<br /> #解析出標題<br /> html_title = soup.html.head.title.string<br /> title = html_title[:len(html_title)-5]<br /> #解析齣電影介紹<br /> try:<br /> intro = soup.find('span',attrs={'class':'all hidden'}).text<br /> except:<br /> try:<br /> node = soup.find('div',attrs={'class':'blank20'}).previousSibling<br /> intro = node.contents[0]+node.contents[2]<br /> except:<br /> try:<br /> contents = soup.find('div',attrs={'class':'blank20'}).previousSibling.previousSibling.text<br /> intro = contents[:len(contents)-22]<br /> except:<br /> intro = u'暫無'</p><p> #取得圖片<br /> html_image = soup('a',href=re.compile('douban.com/lpic'))[0]['href']<br /> data = urllib2.urlopen(html_image).read()<br /> image = '201003/'+html_image[html_image.rfind('/')+1:]<br /> f = file(image_path+image,'wb')<br /> f.write(data)<br /> f.close()</p><p> #解析出地區<br /> try:<br /> soup_obmo = soup.find('div',attrs={'class':'obmo'}).findAll('span')<br /> html_area = soup_obmo[0].nextSibling.split('/')<br /> area = html_area[0].lstrip()<br /> except:<br /> area = ''</p><p> #time = soup_obmo[1].nextSibling.split(' ')[1]<br /> #time = time.strptime(html_time,'%Y-%m-%d')</p><p> #產生電影對象<br /> new_movie = Movie(title=title,intro=intro,area=area,version='暫無',upload_user=user,image=image)<br /> new_movie.save()<br /> try:<br /> actors = soup.find('div',attrs={'id':'info'}).findAll('span')[5].nextSibling.nextSibling.string.split(' ')[0]<br /> actors_list = Actor.objects.filter(name = actors)<br /> if len(actors_list) == 1:<br /> actor = actors_list[0]<br /> new_movie.actors.add(actor)<br /> else:<br /> actor = Actor(name=actors)<br /> actor.save()<br /> new_movie.actors.add(actor)<br /> except:<br /> pass</p><p> #tag<br /> tags = soup.find('div',attrs={'class':'blank20'}).findAll('a')<br /> for tag_html in tags:<br /> tag_str = tag_html.string<br /> if len(tag_str) > 4:<br /> continue<br /> tag_list = Tag.objects.filter(name = tag_str)<br /> if len(tag_list) == 1:<br /> tag = tag_list[0]</p><p> new_movie.tags.add(tag)<br /> else:<br /> tag = Tag(name=tag_str)<br /> tag.save()<br /> new_movie.tags.add(tag)<br /> #try:</p><p> #except Exception.args:<br /> # print "Could not download : %s" % args<br /> print r'download success'<br />

 

 

 

豆瓣的電影頁面並不是很對稱,所以有時候抓取的結果可能會有點出入

 

 

抓取到的電影

 

 

 


 


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.