scrapy爬取豆瓣热门电影

放弃谁都可以,千万不要放弃自己!

目标

采集豆瓣热门电影的基本信息,导演、编剧、主演、上映时间等并将数据存入MySql中。

该项目中使用的开发环境:

python3.6

scrapy1.5

mysql5.7

scrapy编写

scrapy三部曲Item、spider、pipelines,下面我们依次来编写者三个模块的代码。

Item

item中主要定义要采集的字段,我们主要采集电影标题、导演、编剧、主演等字段,具体字段如下:

classDoubanItem(scrapy.Item):

# 标题

title = scrapy.Field()

# 导演

director = scrapy.Field()

# 编剧

writers = scrapy.Field()

# 主演

starring = scrapy.Field()

# 类型

type = scrapy.Field()

# 制片地区

areas = scrapy.Field()

# 语言

language = scrapy.Field()

# 上映日期

date = scrapy.Field()

# 片长

run_time = scrapy.Field()

# 评分

score = scrapy.Field()

# 剧情简介

summary = scrapy.Field()

#电影连接

movie_url = scrapy.Field()

Pipelines

pipelines管道主要用来初始化数据库的连接和相关数据可的操作。所以我们将涉及数据库的操作都放在这里进行,项目中pipelines的代码如下:

classDoubanPipeline(object):

def__init__(self,mysql_host,mysql_user,mysql_password,mysql_db):

self.mysql_host = mysql_host

self.mysql_user = mysql_user

self.mysql_password = mysql_password

self.mysql_db = mysql_db

@classmethod

deffrom_crawler(cls,crawler):

returncls(

mysql_host=crawler.settings.get('MYSQL_HOST'),

mysql_user=crawler.settings.get('MYSQL_USER'),

mysql_password=crawler.settings.get('MYSQL_PASSWORD'),

mysql_db=crawler.settings.get('MYSQL_DB')

)

defopen_spider(self,spider):

self.connection = pymysql.connect(host=self.mysql_host,

user=self.mysql_user,

password=self.mysql_password,

db=self.mysql_db,

charset='utf8mb4',

cursorclass=pymysql.cursors.DictCursor)

self.cursor =self.connection.cursor()

defclose_spider(self,spider):

self.connection.close()

defprocess_item(self,item,spider):

sql ="INSERT INTO `movie` (`title`, `director`,`writers`, `starring`,`type`, `areas`,`language`, `date`"\

", `run_time`,`score`, `summary`, `movie_url`) VALUES (%s, %s,%s, %s,%s, %s,%s, %s,%s, %s,%s,%s)"

try:

# 执行sql语句

self.cursor.execute(sql,(

item['title'],item['director'],item['writers'],item['starring'],item['type'],item['areas'],

item['language'],item['date'],item['run_time'],item['score'],item['summary'],item['movie_url']))

# 向数据库提交

self.connection.commit()

except:

# 发生错误时回滚

self.connection.rollback()

returnitem

spider

spider是scrapy的核心部分,在该项目中应用了scrapy提供的表单模拟登录功能进行登录,在不登录的情况下,有可能会被系统检测到非法操作,从而禁止你的IP访问。经过我对豆瓣热门电影的分析,在列表页利用的是js渲染数据,详情页则没有使用js渲染,故获取列表页是,我们从js中获取数据,利用json.loads将数据转换成json数据,便于数据的提取,详情页利用scrapy提供的xpath解析数据。spider代码如下:

classMovieSpider(scrapy.Spider):

name ='movie'

# allowed_domains = ['https://movie.douban.com']

start_urls ='https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&'\

'page_limit=20&page_start='

login_url ='https://accounts.douban.com/login?source=movie'

defstart_requests(self):

return[FormRequest(url=self.login_url,

formdata={'form_email':'username','form_password':'password'},

callback=self.parse)]

defparse(self,response):

# 请求电影列表js,获取前100部热门电影,每次请求返回20部电影,即循环5次

forpageinrange(5):

page_start = page *20

yieldRequest(url=self.start_urls.format(page_start=page_start),callback=self.parse_url)

defparse_url(self,response):

# 将返回的数据转换成json

subjects = json.loads(response.text)

# 取出电影列表

subject_list = subjects.get('subjects')

# 遍历电影列表

forsubjectinsubject_list:

# 获取电影详情的url

detail_url = subject.get('url')

yieldRequest(url=detail_url,callback=self.parse_detail)

defparse_detail(self,response):

# 导演

director= response.xpath('//div[@id="info"]//span[@class="attrs"]//a[@rel="v:directedBy"]/text()').extract()[]

# 编剧

writers= response.xpath('//div[@id="info"]//span[@class="attrs"]//a/text()').extract()[1]

# 主演

starring=str(response.xpath('//div[@id="info"]//span[@class="attrs"]//a[@rel="v:starring"]/text()').extract())

# 剧情类型

type=str(response.xpath('//div[@id="info"]/span[@property="v:genre"]/text()').extract())

# 上映时间

date=str(response.xpath('//div[@id="info"]/span[@property="v:initialReleaseDate"]/text()').extract())

# 片长

run_time=str(response.xpath('//div[@id="info"]/span[@property="v:runtime"]/text()').extract()[])

# 电影名称

title=''.join(response.xpath('//div[@id="content"]/h1/span/text()').extract())

# 电影评分

score=str(response.xpath('//div[@id="interest_sectl"]//strong[@property="v:average"]/text()').extract()[])

# 电影简介

summary=str(

response.xpath('//div[@id="link-report"]//span[@property="v:summary"]/text()').extract()[]).strip()

regex = re.compile('.*?语言:(.*?)

.*?')

# 电影语言,由于没有具体的标签,所以使用正则解析

language=str(response.xpath('//div[@id="info"]').re(regex)[])

regex = re.compile('.*?制片国家/地区:(.*?)

.*?')

# 电影制片国家/地区,采用正则解析

areas=str(response.xpath('//div[@id="info"]').re(regex)[])

# 电影豆瓣url

movie_url= response.url

item = DoubanItem()

forfieldinitem.fields:

item[field] =eval(field)

yielditem

最后

运行结果就不在这里贴出来了,项目github地址豆瓣电影,需要注意的一个地方,需要将Setting中的ROBOTSTXT_OBEY设置为False,js获取电影列表数据是好像设置了不让爬取。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180611G229FE00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券