爬取的网页,获取子元素内容的方法

今天练习网络爬虫,爬取豆瓣电影Top 250,其中每部电影有排名、评分、电影名、导演等信息,分布在不同的标签下面,而每部电影的所有信息都在一个大的

标签下,因此需要获取子元素的内容。查了一下只看到有人用循环嵌套的方法遍历子元素,感觉略麻烦,后来发现.contents属性可以方便地获取子元素内容,因此采用。
首先爬取第一页的内容,将所有电影的信息存入targets,用for循环遍历(使用break的目的是只研究第一部电影的信息,以节省时间):

import requests
import re
import bs4

def parse_one_page(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'}
    res = requests.get(url, headers=headers)
    soup = bs4.BeautifulSoup(res.text, 'html.parser')
    targets = soup.find_all('div', class_='item')
    for each in targets:
        print(each)
        break

def main():
    global top250
    top250 = []
    url = 'https://movie.douban.com/top250?start={}&filter='.format(25 * 0)
    parse_one_page(url)

if __name__ == '__main__':
    main()

运行结果如下:

<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img alt="肖申克的救赎" class="" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
</a>
</div>
<div class="info">
<div class="hd">
<a class="" href="https://movie.douban.com/subject/1292052/">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港)  /  刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim
Robbins /...<br/>
                            1994 / 美国 / 犯罪 剧情
                        </p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.6</span>
<span content="10.0" property="v:best"></span>
<span>1338214人评价</span>
</div>
<p class="quote">
<span class="inq">希望让人自由。</span>
</p>
</div>
</div>
</div>

可以对比这一部分的源代码:

<div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https://movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https://movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救赎</span>
                                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                                <span class="other">&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                        </a>


                            <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                        </p>

                        
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v:average">9.6</span>
                                <span property="v:best" content="10.0"></span>
                                <span>1338214人评价</span>
                        </div>

                            <p class="quote">
                                <span class="inq">希望让人自由。</span>
                            </p>
                    </div>
                </div>
            </div>

可以看出,第一部电影的信息被打印了出来,要想获取具体某一项信息,尝试调用.contents属性print(each.contents)

['\n', <div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img alt="肖申克的救赎" class="" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
</a>
</div>, '\n', <div class="info">
<div class="hd">
<a class="" href="https://movie.douban.com/subject/1292052/">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞()  /  刺激1995()</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim
Robbins /...<br/>
                            1994 / 美国 / 犯罪 剧情
                        </p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.6</span>
<span content="10.0" property="v:best"></span>
<span>1338863人评价</span>
</div>
<p class="quote">
<span class="inq">希望让人自由。</span>
</p>
</div>
</div>, '\n']

发现得到一个list,每一个子元素成为list的一个元素,两两之间有换行符,list收尾也是换行符。由此推断<div class="pic">子元素为each.contents[1],由此类推,电影排名为each.contents[1].contents[1].text,电影名为each.contents[3].contents[1].contents[1].contents[1].text,电影评分为each.contents[3].contents[3].contents[3].contents[3].text,等等。最后,将每一部电影的信息append到列表中,并写入Excel。完整代码如下:

import requests
import re
import bs4
import openpyxl


def parse_one_page(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'}
    res = requests.get(url, headers=headers)
    soup = bs4.BeautifulSoup(res.text, 'html.parser')
    targets = soup.find_all('div', class_='item')
    for each in targets:
        rank = each.contents[1].contents[1].text
        name = each.contents[3].contents[1].contents[1].contents[1].text
        rating = each.contents[3].contents[3].contents[3].contents[3].text
        try:
            quote = each.contents[3].contents[3].contents[5].contents[1].text
        except:
            quote = ''
        s = each.contents[3].contents[3].contents[1].text
        pattern = '导演: (.*?)\s主演: (.*?)...\s+(\d+)\s/\s(.*?)\s/\s(.*)\s+'
        try:
            director = re.search(pattern, s).group(1)
        except:
            director = ''
        try:
            hero = re.search(pattern, s).group(2)
        except:
            hero = ''
        try:
            year = re.search(pattern, s).group(3)
        except:
            year = ''
        try:
            region = re.search(pattern, s).group(4)
        except:
            region = ''
        try:
            genre = re.search(pattern, s).group(5)
        except:
            genre = ''
        top250.append([rank, name, rating, year, region, genre, director, hero, quote])
        #break
        

def main():
    global top250
    top250 = []

    for i in range(10):
        url = 'https://movie.douban.com/top250?start={}&filter='.format(25 * i)
        parse_one_page(url)
    
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.append(['rank', 'name', 'rating', 'year', 'region', 'genre', 'director', 'hero', 'quote'])

    for each in top250:
        ws.append(each)
    wb.save('douban.xlsx')

if __name__ == '__main__':
    main()

以上代码鲁棒性还不够好,原因是Top 250的页面显示的信息有限,有时候导演名字过长,“演员”二字显示不完整,导致正则表达式匹配不上,于是演员等信息就不显示了。更好的方案是获取每一部电影的URL,然后逐一解析。

猜你喜欢

转载自blog.csdn.net/weixin_43957391/article/details/88071940
今日推荐