放弃谁都可以,千万不要放弃自己!
目标
采集豆瓣热门电影的基本信息,导演、编剧、主演、上映时间等并将数据存入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获取电影列表数据是好像设置了不让爬取。
领取专属 10元无门槛券
私享最新 技术干货