美文网首页
《Python 核心技术与实战》 学习笔记 Day19 揭秘 P

《Python 核心技术与实战》 学习笔记 Day19 揭秘 P

作者: _相信自己_ | 来源:发表于2023-02-02 23:19 被阅读0次

    从一个爬虫说起

    爬虫,就是互联网的蜘蛛,在搜索引擎诞生之时,与其一同来到世上。爬虫每秒钟都会爬取大量的网页,提取关键信息后存储在数据库中,以便日后分析。爬虫有非常简单的 Python 十行代码实现,也有 Google 那样的全球分布式爬虫的上百万行代码,分布在内部上万台服务器上,对全世界的信息进行嗅探。
    简单的爬虫例子:

    
    import time
    
    def crawl_page(url):
        print('crawling {}'.format(url))
        sleep_time = int(url.split('_')[-1])
        time.sleep(sleep_time)
        print('OK {}'.format(url))
    
    def main(urls):
        for url in urls:
            crawl_page(url)
    
    %time main(['url_1', 'url_2', 'url_3', 'url_4'])
    
    ########## 输出 ##########
    
    crawling url_1
    OK url_1
    crawling url_2
    OK url_2
    crawling url_3
    OK url_3
    crawling url_4
    OK url_4
    Wall time: 10 s
    

    一个很简单的思路出现了——我们这种爬取操作,完全可以并发化。我们就来看看使用协程怎么写。

    
    import asyncio
    
    async def crawl_page(url):
        print('crawling {}'.format(url))
        sleep_time = int(url.split('_')[-1])
        await asyncio.sleep(sleep_time)
        print('OK {}'.format(url))
    
    async def main(urls):
        for url in urls:
            await crawl_page(url)
    
    %time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))
    
    ########## 输出 ##########
    
    crawling url_1
    OK url_1
    crawling url_2
    OK url_2
    crawling url_3
    OK url_3
    crawling url_4
    OK url_4
    Wall time: 10 s
    

    实战:豆瓣近日推荐电影爬虫

    任务描述:https://movie.douban.com/cinema/later/beijing/ 这个页面描述了北京最近上映的电影,你能否通过 Python 得到这些电影的名称、上映时间和海报呢?这个页面的海报是缩小版的,我希望你能从具体的电影描述页面中抓取到海报。

    
    import requests
    from bs4 import BeautifulSoup
    
    def main():
        url = "https://movie.douban.com/cinema/later/beijing/"
        init_page = requests.get(url).content
        init_soup = BeautifulSoup(init_page, 'lxml')
    
        all_movies = init_soup.find('div', id="showing-soon")
        for each_movie in all_movies.find_all('div', class_="item"):
            all_a_tag = each_movie.find_all('a')
            all_li_tag = each_movie.find_all('li')
    
            movie_name = all_a_tag[1].text
            url_to_fetch = all_a_tag[1]['href']
            movie_date = all_li_tag[0].text
    
            response_item = requests.get(url_to_fetch).content
            soup_item = BeautifulSoup(response_item, 'lxml')
            img_tag = soup_item.find('img')
    
            print('{} {} {}'.format(movie_name, movie_date, img_tag['src']))
    
    %time main()
    
    ########## 输出 ##########
    
    阿拉丁 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2553992741.jpg
    龙珠超:布罗利 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2557371503.jpg
    五月天人生无限公司 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2554324453.jpg
    ... ...
    直播攻略 06月04日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2555957974.jpg
    Wall time: 56.6 s
    
    import asyncio
    import aiohttp
    
    from bs4 import BeautifulSoup
    
    async def fetch_content(url):
        async with aiohttp.ClientSession(
            headers=header, connector=aiohttp.TCPConnector(ssl=False)
        ) as session:
            async with session.get(url) as response:
                return await response.text()
    
    async def main():
        url = "https://movie.douban.com/cinema/later/beijing/"
        init_page = await fetch_content(url)
        init_soup = BeautifulSoup(init_page, 'lxml')
    
        movie_names, urls_to_fetch, movie_dates = [], [], []
    
        all_movies = init_soup.find('div', id="showing-soon")
        for each_movie in all_movies.find_all('div', class_="item"):
            all_a_tag = each_movie.find_all('a')
            all_li_tag = each_movie.find_all('li')
    
            movie_names.append(all_a_tag[1].text)
            urls_to_fetch.append(all_a_tag[1]['href'])
            movie_dates.append(all_li_tag[0].text)
    
        tasks = [fetch_content(url) for url in urls_to_fetch]
        pages = await asyncio.gather(*tasks)
    
        for movie_name, movie_date, page in zip(movie_names, movie_dates, pages):
            soup_item = BeautifulSoup(page, 'lxml')
            img_tag = soup_item.find('img')
    
            print('{} {} {}'.format(movie_name, movie_date, img_tag['src']))
    
    %time asyncio.run(main())
    
    ########## 输出 ##########
    
    阿拉丁 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2553992741.jpg
    龙珠超:布罗利 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2557371503.jpg
    五月天人生无限公司 05月24日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2554324453.jpg
    ... ...
    直播攻略 06月04日 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2555957974.jpg
    Wall time: 4.98 s
    

    总结

    • 协程和多线程的区别,主要在于两点,一是协程为单线程;二是协程由用户决定,在哪些地方交出控制权,切换到下一个任务。
    • 协程的写法更加简洁清晰,把 async / await 语法和 create_task 结合来用,对于中小级别的并发需求已经毫无压力。
    • 写协程程序的时候,你的脑海中要有清晰的事件循环概念,知道程序在什么时候需要暂停、等待 I/O,什么时候需要一并执行到底。

    相关文章

      网友评论

          本文标题:《Python 核心技术与实战》 学习笔记 Day19 揭秘 P

          本文链接:https://www.haomeiwen.com/subject/odvghdtx.html