Scrapy爬取豆瓣分类电影

由于毕业设计推荐系统需要大量电影信息数据,从豆瓣电影爬取了一万多条电影数据,记录一下第一次爬数据,同时感谢豆瓣电影平台提供的数据。

爬取思想:豆瓣选电影页面用的是JS动态渲染,用谷歌浏览器查看点击加载时发送的URL,解析拼接为新的URL,在Scrapy框架中以该URL为入口,每次获取到20个电影数据,再分别访问20个电影的URL地址获取到详细的电影数据,用Xpath解析html页面。

具体步骤如下:

1.解析拼接url

访问豆瓣页面点击加载更多,谷歌查看此时后台发现它发送了一个请求:

https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=20

通过这个URL请求可以获取到20条JSON格式的电影数据,每次通过对start参数自增20获取到数据。

2.获取数据

请求url获取到如下的JSON格式数据:

解析获取JSON格式数据: 

dicts=json.loads(response.body)['data']

循环20个电影列表访问每个电影详情页的url获取HTML页面

movie_url=dict['url']
movie_html=requests.get(movie_url)
root = etree.HTML(movie_html.content)
movies=root.xpath('//div[@id="content"]')

用Xpath解析HTML页面元素获取到数据,并且给item

                   movie_id=movie_url[33:-1]
                    movie_title=each.xpath('.//h1/span[1]/text()')
                    movie_title = ",".join(movie_title)
                    release_year=each.xpath('.//h1/span[2]/text()')
                    release_year = ",".join(release_year).split(')')[0].split('(')[1]
                    movie_img=each.xpath('.//div[@id="mainpic"]/a/img/@src')
                    movie_img = ",".join(movie_img)
                    director=each.xpath('.//div[@id="info"]/span[1]/span[2]/a/text()')
                    director=",".join(director)
                    screenwriter=each.xpath('.//div[@id="info"]/span[2]/span[2]/a/text()')
                    screenwriter = ",".join(screenwriter)
                    starring=each.xpath('.//div[@id="info"]//a[@rel="v:starring"]/text()')
                    starring = ",".join(starring)
                    type=each.xpath('.//div[@id="info"]/span[@property="v:genre"]/text()')
                    type = ",".join(type)
                    production_country=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="制片国家/地区:"]][following-sibling::br]')[0]
                    language=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="语言:"]][following-sibling::br]')[0]
                    release_time=each.xpath('.//div[@id="info"]/span[@property="v:initialReleaseDate"]/text()')
                    release_time = ",".join(release_time)
                    length=each.xpath('.//div[@id="info"]/span[@property="v:runtime"]/text()')
                    length = ",".join(length)
                    url=movie_url
                    imdb_link=each.xpath('.//div[@id="info"]/a/@href')
                    imdb_link = ",".join(imdb_link)
                    alias=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="又名:"]][following-sibling::br]')
                    if alias:
                        alias=alias[0]
                    score=each.xpath('.//div[@id="interest_sectl"]/div[1]/div[2]/strong/text()')
                    score = ",".join(score)
                    synopsis=each.xpath('.//div[@id="link-report"]/span/text()')
                    synopsis = ",".join(synopsis).replace(" ","").replace("\u3000","")

重构URL地址,再进行获取电影数据

        url = response.url
        url = url.split('=')
        url[-1] = str(int(url[-1])+20)
        next_url = '='.join(url)
        yield scrapy.Request(next_url,callback=self.parse,dont_filter=True)

3.将数据存到Mysql数据库

class DoubanmoviePipeline(object):

    def __init__(self,dbpool):
        self.dbpool=dbpool

    @classmethod
    def from_settings(cls,settings):
        dbparams=dict(
            host=settings['MYSQL_HOST'],
            db=settings['MYSQL_DBNAME'],
            user=settings['MYSQL_USER'],
            password=settings['MYSQL_PASSWORD'],
            charset='utf8',
            cursorclass=pymysql.cursors.DictCursor,
            use_unicode=False,
        )
        dbpool=adbapi.ConnectionPool('pymysql',**dbparams)
        return cls(dbpool)

    def process_item(self, item, spider):
        asynitem = copy.deepcopy(item)
        if isinstance(item,DoubanmovieItem):
            query=self.dbpool.runInteraction(self._conditional_insert_movie,asynitem)
            query.addErrback(self._handle_error,asynitem,spider)
        elif isinstance(item,MovieRcmdItem):
            query=self.dbpool.runInteraction(self._conditional_insert_moviercmd,asynitem)
            query.addErrback(self._handle_error,asynitem,spider)
        return asynitem

    def _conditional_insert_movie(self,tx,item):
        sql="insert into movie(movie_id,movie_title,movie_img,director,screenwriter,starring,type,production_country,language,release_time,length,release_year,url,imdb_link,alias,score,synopsis) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        params=(item['movie_id'], item['movie_title'],item['movie_img'],item['director'],item['screenwriter'],item['starring'],item['type'], item['production_country'],item['language'],item['release_time'],item['length'],item['release_year'],item['url'], item['imdb_link'],item['alias'],item['score'],item['synopsis'])
        tx.execute(sql,params)

注意对数据进行深拷贝,否则爬取速度太快已爬取的数据还没存入数据库,后面的数据就已经覆盖掉前面的数据。

4.反爬虫策略

  • 在setting里面禁用cookie
  • 使用IP代理,购买IP代理池(这里买的是阿布云的IP代理)或者网上找IP代理池
  • 随机UserAgent头

 

     最后爬取了一万多条数据,如果只是做推荐系统的话,不需要太多的国家等这么多详细信息,网上也有很多已经爬取好的数据,我这里是做的Web推荐系统,所以需要更多详细的电影数据才自己按需求爬取的数据。另外,如果只是需要少量数据的话可以使用一些爬虫软件,比如八爪鱼、火车头、后羿采集器。我个人比较喜好后羿采集器,感觉定制规则方便很多。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值