由于毕业设计推荐系统需要大量电影信息数据,从豆瓣电影爬取了一万多条电影数据,记录一下第一次爬数据,同时感谢豆瓣电影平台提供的数据。
爬取思想:豆瓣选电影页面用的是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推荐系统,所以需要更多详细的电影数据才自己按需求爬取的数据。另外,如果只是需要少量数据的话可以使用一些爬虫软件,比如八爪鱼、火车头、后羿采集器。我个人比较喜好后羿采集器,感觉定制规则方便很多。