美文网首页
2018-07-25爬取今日头条风景图片

2018-07-25爬取今日头条风景图片

作者: 纳米片 | 来源:发表于2018-07-25 18:24 被阅读0次

    1、页面分析

    首先,我们再今日头条的首页搜索框输入“风景”搜索,如图所示:

    搜索结果
    打开开发者模式,刷新页面,查看第一个请求的URL,https://www.toutiao.com/search/?keyword=%E9%A3%8E%E6%99%AF,查看选项卡Response,都是一些JavaScript代码,并没有我们需要的内容,可以初步判定是由Ajax加载,然后用JavaScript渲染,切换到XHR过滤选项卡,找到第一条结果,Preview中查看到一个title字段,它正好是第一个数据的标题。
    Ajax请求结果
    data字段中,有一项image_list字段,展开后发现是一些url链接,我们打开它发现只是一些缩略图,并不是我们想要的。
    data字段展开
    所以,我们只能通过获取数据的URL链接,跳转到图片所在的真实页面获取图片的url。
    我们发现每一条数据中都有一个article_url字段,它就是这条数据的url,打开后可以看多所有图片。
    数据中所有图片
    查看网页的源代码,发现都已一些js代码。但其中有一个articleInfo字段,可以看到所有图片的url链接。
    源代码
    我们可以通过正则表达式,将所有的url提取出来。
    content = re.search('articleInfo:.*?content:(.*?)groupId', html, re.S)
         if content:
              pattern = re.compile('(http://.*?)&', re.S)
              image_urls = re.findall(pattern, content.group(1))
              for url in image_urls:
                   yield url
    

    但是今日头条的各条数据加载情况很多,其中还有一种情况如下:


    组图形式

    查看其网页源代码,发现有一组json数据,指定了图片的url,width,height。


    网页源代码
    这里依然用正则表达式将url提取出来。
    pattern = re.compile('url_list(.*?),', re.S)
    contents = re.findall(pattern, html)
    for content in contents:
    #利用sub方法将content字符串第15至倒数第2的值中的\\替换掉
              yield re.sub(r'\\', '', content[15:-2])
    

    运行结果:


    运行结果

    其中有部分数据并没有进行抓取,比如含视频的,代码还有需要完善的地方。
    附上源代码:

    import requests, re, os
    from hashlib import md5
    from multiprocessing import Pool
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',
    }
    
    #获取页面源代码
    def get_page(offset):
        params = {
            'offset': offset,
            'format': 'json',
            'keyword': '风景',
            'autoload': True,
            'count': 20,
            'cur_tab': 1,
            'from': 'search_tab'
        }
        url = 'https://www.toutiao.com/search_content/?'
        try:
            response = requests.get(url=url, params=params, headers=headers)
            if response.status_code == 200:
                return response.json()
        except requests.ConnectionError as e:
            print('Error', e.args)
            return None
    
    #获取文章标题和链接
    def get_image_url(json):
        if json.get('data'):
            for item in json.get('data'):
                if item.get('article_url'):
                    yield {
                        'title': item.get('title'),
                        'article_url': item.get('article_url')
                    }
    
    #获取图片链接
    def get_images(image_url):
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
            }
            response = requests.get(image_url, headers=headers)
            if response.status_code == 200:
                html = response.text
                if 'articleInfo' in html:
                    content = re.search('articleInfo:.*?content:(.*?)groupId', html, re.S)
                    if content:
                        pattern = re.compile('(http://.*?)&', re.S)
                        image_urls = re.findall(pattern, content.group(1))
                        for url in image_urls:
                            #print(url)
                            yield url
                elif 'galleryInfo' in html:
                    pattern = re.compile('url_list(.*?),', re.S)
                    contents = re.findall(pattern, html)
                    for content in contents:
                        #print(re.sub(r'\\', '', content[15:-2]))
                        yield re.sub(r'\\', '', content[15:-2])
        except requests.ConnectionError as e:
            print('ERROR:', e.args)
    
    #下载图片
    def save_image(item):
        if not os.path.exists(item.get('title')):
            os.mkdir(item.get('title'))
        try:
            for im in get_images(item.get('article_url')):
                response = requests.get(im)
                if response.status_code == 200:
                    file_path = '{0}/{1}.{2}'.format(item.get('title'), md5(response.content).hexdigest(), 'jpg')
                    if not os.path.exists(file_path):
                        with open(file_path, 'wb') as f:
                            f.write(response.content)
                    else:
                        print('已下载', file_path)
        except requests.ConnectionError as e:
            print('Failed to Save Image')
    
    def main(offset):
        json = get_page(offset)
        for item in get_image_url(json):
            print(item)
            save_image(item)
    
    GROUP_START = 1
    GROUP_END = 5
    
    if __name__ == '__main__':
        pool = Pool()
        groups = ([x * 20 for x in range(GROUP_START, GROUP_END+1)])
        pool.map(main, groups)
        pool.close()
        pool.join()
    

    相关文章

      网友评论

          本文标题:2018-07-25爬取今日头条风景图片

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