Python爬虫学习笔记 -- 爬取豆瓣电影top250的信息

Python爬虫学习笔记 -- 用Scrapy爬取豆瓣电影top250的信息


代码存放地址: https://github.com/xyls2011/python/tree/master/dbmovie
爬取目标网址: https://movie.douban.com/top250


知识点:Scrapy框架,Scrapy的CSS选择器用法,Python基础知识,re正则用法


参考文章: https://blog.csdn.net/superliugang/article/details/88947700

1. scrapy 中的css使用方法:

①response.css('a')返回的是selector对象,

②response.css('a').extract()返回的是a标签对象

③response.css('a::text').extract_first()返回的是第一个a标签中文本的值

④response.css('a::attr(href)').extract_first()返回的是第一个a标签中href属性的值

⑤response.css('a[href*=image]::attr(href)').extract()返回所有a标签中href属性包含image的值

⑥response.css('a[href*=image] img::attr(src)').extract()返回所有a标签下image标签的src属性

CSS3 选择器

在 CSS 中,选择器是一种模式,用于选择需要添加样式的元素。

"CSS" 列指示该属性是在哪个 CSS 版本中定义的。(CSS1、CSS2 还是 CSS3。)

选择器例子例子描述CSS
.class.intro选择 class="intro" 的所有元素。1
#id#firstname选择 id="firstname" 的所有元素。1
**选择所有元素。2
elementp选择所有 <p> 元素。1
element,elementdiv,p选择所有 <div> 元素和所有 <p> 元素。1
element elementdiv p选择 <div> 元素内部的所有 <p> 元素。1
element>elementdiv>p选择父元素为 <div> 元素的所有 <p> 元素。2
element+elementdiv+p选择紧接在 <div> 元素之后的所有 <p> 元素。2
[attribute][target]选择带有 target 属性所有元素。2
[attribute=value][target=_blank]选择 target="_blank" 的所有元素。2
[attribute~=value][title~=flower]选择 title 属性包含单词 "flower" 的所有元素。2
[attribute|=value][lang|=en]选择 lang 属性值以 "en" 开头的所有元素。2
:linka:link选择所有未被访问的链接。1
:visiteda:visited选择所有已被访问的链接。1
:activea:active选择活动链接。1
:hovera:hover选择鼠标指针位于其上的链接。1
:focusinput:focus选择获得焦点的 input 元素。2
:first-letterp:first-letter选择每个 <p> 元素的首字母。1
:first-linep:first-line选择每个 <p> 元素的首行。1
:first-childp:first-child选择属于父元素的第一个子元素的每个 <p> 元素。2
:beforep:before在每个 <p> 元素的内容之前插入内容。2
:afterp:after在每个 <p> 元素的内容之后插入内容。2
:lang(language)p:lang(it)选择带有以 "it" 开头的 lang 属性值的每个 <p> 元素。2
element1~element2p~ul选择前面有 <p> 元素的每个 <ul> 元素。3
[attribute^=value]a[src^="https"]选择其 src 属性值以 "https" 开头的每个 <a> 元素。3
[attribute$=value]a[src$=".pdf"]选择其 src 属性以 ".pdf" 结尾的所有 <a> 元素。3
[attribute*=value]a[src*="abc"]选择其 src 属性中包含 "abc" 子串的每个 <a> 元素。3
:first-of-typep:first-of-type选择属于其父元素的首个 <p> 元素的每个 <p> 元素。3
:last-of-typep:last-of-type选择属于其父元素的最后 <p> 元素的每个 <p> 元素。3
:only-of-typep:only-of-type选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。3
:only-childp:only-child选择属于其父元素的唯一子元素的每个 <p> 元素。3
:nth-child(n)p:nth-child(2)选择属于其父元素的第二个子元素的每个 <p> 元素。3
:nth-last-child(n)p:nth-last-child(2)同上,从最后一个子元素开始计数。3
:nth-of-type(n)p:nth-of-type(2)选择属于其父元素第二个 <p> 元素的每个 <p> 元素。3
:nth-last-of-type(n)p:nth-last-of-type(2)同上,但是从最后一个子元素开始计数。3
:last-childp:last-child选择属于其父元素最后一个子元素每个 <p> 元素。3
:root:root选择文档的根元素。3
:emptyp:empty选择没有子元素的每个 <p> 元素(包括文本节点)。3
:target#news:target选择当前活动的 #news 元素。3
:enabledinput:enabled选择每个启用的 <input> 元素。3
:disabledinput:disabled选择每个禁用的 <input> 元素3
:checkedinput:checked选择每个被选中的 <input> 元素。3
:not(selector):not(p)选择非 <p> 元素的每个元素。3
::selection::selection选择被用户选取的元素部分。3

2. 爬虫代码逻辑

items.py代码:

import scrapy
class DbmovieItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    rating = scrapy.Field()
    desc = scrapy.Field()

dbmovie250.py代码:

import scrapy
from dbmovie.items import DbmovieItem


class Dbmovie250Spider(scrapy.Spider):
    name = 'dbmovie250'
    # allowed_domains = ['movie.douban.com/top250']
    start_urls = ['https://movie.douban.com/top250']
    header = {
        'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
    }

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse, headers=self.header)

    def parse(self, response):
        for quote in response.css('div.item'):
            item = DbmovieItem()
            item['title'] = quote.css('div.info div.hd a span.title::text').extract_first()
            item['rating'] = quote.css('div.info div.bd div.star span.rating_num::text').extract_first()
            item['desc'] = quote.css('div.info div.bd p.quote span.inq::text').extract_first()
            yield item

        next_url = response.css('div.paginator span.next a::attr(href)').extract()
        print(next_url)
        if next_url:
            next_url = 'https://movie.douban.com/top250' + next_url[0]
            print(next_url)
            yield scrapy.Request(url=next_url, headers=self.header)

参考文章:Scrapy爬取豆瓣电影top250
运行爬虫:scrapy crawl dbmovie250 -o douban_movie.csv -t csv

下载下来的csv文件没有按定义的字段排序,需要在settings.py加入FEED_EXPORT_FIELDS = [“title”, “rating”, “desc”],爬取结果如下:

结果如下:

title,rating,desc
肖申克的救赎,9.6,希望让人自由。
霸王别姬,9.6,风华绝代。
这个杀手不太冷,9.4,怪蜀黍和小萝莉不得不说的故事。
阿甘正传,9.4,一部美国近现代史。
美丽人生,9.5,最美的谎言。
泰坦尼克号,9.3,失去的才是永恒的。 
千与千寻,9.3,最好的宫崎骏,最好的久石让。 
辛德勒的名单,9.5,拯救一个人,就是拯救整个世界。

3. 正则实现爬取豆瓣top250

import requests
import re
url = 'https://movie.douban.com/top250'
#访问网站,并获得回复和网页原代码
response = requests.get(url)
response.encoding = 'utf-8'
html = response.text
title = re.findall(r'<h1>(.*?)</h1>',html)[0]
#打开文本文件,并以‘title’为文件名
fb = open('%s.txt' % title, 'w', encoding='utf-8')
#用正则表达式来获得当前页面的排名
ranks = re.findall(r'<em class="">(.*?)</em>.*?<a href="(.*?)">.*?<img width="100" alt="(.*?)" src="(.*?)" class="">',html,re.S)
#用正则表达式来获得当前页面的分数
points = re.findall(r'<span class="rating_num" property="v:average">(.*?)</span>.*?<span>(.*?)</span>',html,re.S)
#用正则表达式来获得后面排名的网页链接
next_list = re.findall(r'<span class="thispage">1</span>(.*?)<span class="next">',html,re.S)[0]
print(next_list)
next_list = re.findall(r'<a href="(.*?)" >.*?</a>',next_list,re.S)
print(next_list)
# 先处理1—25名的数据
for i in range(0, 25):
    number, movie, name, picture = ranks[i]
    score, people = points[i]
    fb.write(number + '  ' + name)
    fb.write('\n')
    fb.write('电影链接:' + movie)
    fb.write('\n')
    fb.write('电影海报链接:' + picture)
    fb.write('\n')
    fb.write(people + '为:' + score + '分' + '\n')
#处理剩余排名的数据
for next in next_list:
    #把获得的链接补全,便于正常访问
    next = "https://movie.douban.com/top250%s" % next
    #获得剩余排名的电影的数据
    next_response = requests.get(next)
    # next_response.encoding = 'utf-8'
    next_html = next_response.text
    ranks = re.findall(r'<em class="">(.*?)</em>.*?<a href="(.*?)">.*?<img width="100" alt="(.*?)" src="(.*?)" class="">', next_html, re.S)
    points = re.findall(r'<span class="rating_num" property="v:average">(.*?)</span>.*?<span>(.*?)</span>', next_html, re.S)
    for i in range(0,25):
        number, movie, name, picture = ranks[i]
        score, people = points[i]
        fb.write(number + '  ' + name)
        fb.write('\n')
        fb.write('电影链接:' + movie)
        fb.write('\n')
        fb.write('电影海报链接:' + picture)
        fb.write('\n')
        fb.write(people + '为:' + score + '分' + '\n')
#完成访问后关闭文本文件和访问请求
fb.close()
response.close()

爬取结果:
1 肖申克的救赎
电影链接:https://movie.douban.com/subject/1292052/
电影海报链接:https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg
1444001人评价为:9.6分
2 霸王别姬
电影链接:https://movie.douban.com/subject/1291546/
电影海报链接:https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1910813120.jpg
1070028人评价为:9.6分
参考文章:https://blog.csdn.net/be_BetterMan/article/details/80786356

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值