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

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爬取今日头条风景图片)