Python爬虫(一)别说话快上车:改写第一个爬虫程序

Python爬虫(一)别说话快上车:改写第一个爬虫程序

背景交代:因为准备研究生的一门选修课“可视化”期末作业,需要将几个csv文件的电影数据可视化。我想用电影海报来可视化07-11年最赚好莱坞电影总票房数据,因此开始接触爬虫,至今(2015.4.25)不到一周……将来或许一些科研项目搜集素材会用到,所以打算把学习爬虫技术作为一个长期任务,开挖新坑。

本篇的爬虫是基于Python2.7+Scrapy编写的。关于开发环境的搭建可见
http://www.cnblogs.com/txw1958/archive/2012/07/12/scrapy_installation_introduce.html
本程序的部分代码参考了
http://www.cnblogs.com/Shirlies/p/4537931.html
不知为何我的爬虫总是无法成功爬豆瓣(403错误,被屏蔽),所以改成了爬imdb。

items.py

这个文件用来定义要抓取的项目的成员

#coding=utf-8

#Define here the models for your scraped items

from scrapy.item import Item, Field

class TutorialItem(Item):

    #define the fields for your item here like:
    movie_name = Field()
    movie_picture = Field()

pipelines.py

这部分我没有修改,照搬的原文内容。

imdb_spider.py

可能是scrapy版本的关系,使用原教程里的’HtmlXpathSelector.select()’等函数会提示过时函数的warning,并且推荐使用’Selector.xpath()’,所以做了修改。还有更多关于数据过滤的内容,写在代码注释里吧

#coding=utf-8

from scrapy.spiders import Spider
from scrapy.http import Request
from scrapy.selector import Selector #原文里的HtmlXpathSelector全部换成了Selector
from tutorial.items import TutorialItem
import re
import urllib

class ImdbSpider(Spider):
    name = "imdb"
    allowed_domains = ["www.imdb.com"]
    start_urls = []

    def start_requests(self):
        file_object = open('movie_name.txt','r')  #电影名存储在movie_name.txt文件里

        try:
            url_head = "http://www.imdb.com/find?ref_=nv_sr_fn&q="  #imdb电影搜索的url头
            for line in file_object:
                self.start_urls.append(url_head + line + '&s=tt')
                #&s=tt是限定搜索仅限标题,可以过滤掉电影名正好是影人名导致爬到影人照片的情况

            for url in self.start_urls:
                yield self.make_requests_from_url(url)
        finally:
            file_object.close()

    def parse(self, response):
        #open("test.html",'wb').write(response.body)#测试response是否正确

        hxs = Selector(response)
        #为了防止爬到空白图片(如缺少海报的电影或者TV Series),加一个循环,遇到空白预览图往下搜
        i = 1
        movie_pic = hxs.xpath('id("main")/div/div[2]/table/tr[1]/td[1]/a/img/@src').extract()
        while movie_pic[0].find('nopicture') == -1:
            i++
            movie_pic = hxs.xpath('id("main")/div/div[2]/table/tr[%d]/td[1]/a/img/@src' % i).extract()
            #如果是所有的结果都没有预览图的情况,还是要跳出循环的
            if not movie_pic:
                break
        #open("movie_pic.txt", 'w').write(str(movie_pic))#测试海报url是否正确

        #为了减少request量,这里使用了一个偷懒的方法:
        #因为imdb搜索结果页的海报预览图和电影具体信息页面的海报预览图在url上只有表示尺寸值的字符串差别,
        #所以这里直接替换,就不需要从@href的链接访问进去了。如果需要更大的海报,到相应的页面去找,可以发现只要把
        #“UX182_CR0,0,32,44_AL_.jpg”换成“SX640_SY720_.jpg”就行了
        if movie_pic:
            movie_pic[0]=movie_pic[0].replace('32','182')
            movie_pic[0]=movie_pic[0].replace('44','268')

        #下载海报预览图
        item = TutorialItem()
        item['movie_picture'] = ''.join(movie_pic).strip()
        movie_name_file = open('movie_name.txt','r')
        try:
            for line in movie_name_file:
                item['movie_name'] = line.strip()
                if movie_pic:
                    urllib.urlretrieve(movie_pic[0].strip(),'pictures/' + line.strip() + '.jpg')
        finally:
            movie_name_file.close()
        yield item

main.py

主函数和原文类似,稍稍修改了部分,使之具有读取csv文件的功能,以及添加了一些用于数据过滤的代码

#coding=utf-8

import os
import csv
#read csv
csvfile = file('movie2011.csv','r')
reader = csv.reader(csvfile)
movie_nm = []

for line in reader:
    if line[0] != '' && line[0]!='Film' && line[0]!= 'Average':
        movie_nm.append(line[0])    
csvfile.close()

#读取电影数据
try:
    for x in movie_nm:
        #数据整理
        write_name = x.replace('_','+')#换掉空格,否则搜索时会丢失后面的内容
        write_name = write_name.replace('\'','')
        write_name = write_name.replace(':', '%3A')#片名中的冒号在url中是以%3A表示的
        if write_name.find('(')!= -1:
            write_name = write_name[:write_name.find('(')]#去掉括号内容,否则影响搜索结果
        #print "name is :" + write_name

        #把电影名写到中间文件中去,让爬虫读取。和原文机制是一样的,写一个,爬一个
        movie_name_file = open('movie_name.txt','w')
        try:
            movie_name_file.write(write_name)
        finally:
            movie_name_file.close()

        #该爬虫程序会从movie_name中读取电影名来爬虫
        os.system(r"scrapy crawl imdb")

finally:
    print "finished crawl"

爬完之后就得到了相应的海报

可视化

计算07年~11年的这些电影总票房,然后在world里截个图,作为拼接的底片。然后使用专门做拼接马赛克图的AndreaMosaic软件拼接这些海报(一共大概650张海报),就得到如下效果了:

这篇文章只是一个往容器里塞东西式改写的爬虫,没有涉及到爬虫核心的技术,更多描述在数据处理和结果过滤等方面,很浅。不过也算是一个根据本地文件爬电影海报的爬虫参考啦

你可能感兴趣的:(Python)