爬取今日头条美女图片

推荐下我自己创建的Python学习交流群923414804,这是Python学习交流的地方,不管你是小白还是大牛,小编都欢迎,不定期分享干货,包括我整理的一份适合零基础学习Python的资料和入门教程。


笔者是头条的深度使用者,经常用头条完成“看片”大业。若不信的话可以试试在头条搜索街拍,返回的都是一道道靓丽的风景线。

想把图片存下来,该怎么办呢?我们可以用Python爬虫啊。

1、工具

Python3.5,Sublime Text,Windows 7

2、分析(第三步有完整代码)

可以看到搜索结果默认返回了 20 篇文章,当页面滚动到底部时头条通过 ajax 加载更多文章,浏览器按下 F12 打开调试工具(我的是 Chrome),点击 Network 选项,尝试加载更多的文章,可以看到相关的 http 请求:

此次返回Request URL:

http://www.toutiao.com/search_content/?offset=20&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&cur_tab=1

来试试返回了什么

import json

from urllib import request

url = "http://www.toutiao.com/search_content/?offset=20&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&cur_tab=1"

with request.urlopen(url) as res:

    d = json.loads(res.read().decode())

    print(d)

发现我们需要的东西在'data'里,打开一篇文章,来试试如何下载单篇图片。

import json

from urllib import request

url = 'http://www.toutiao.com/a6314996711535444226/#p=1'

with request.urlopen(url) as res:

    soup = BeautifulSoup(res.read().decode(errors='ignore'), 'html.parser')

    article_main = soup.find('div', id='article-main')

    photo_list = [photo.get('src') for photo in article_main.find_all('img') if photo.get('src')]

    print(photo_list)


输出

['http://p3.pstatp.com/large/159f00010b30d6736512', 'http://p1.pstatp.com/large/1534000488c40143b9ce', 'http://p3.pstatp.com/large/159d0001834ff61ccb8c', 'http://p1.pstatp.com/large/1534000488c1cd02b5ed']

首先用BeautifulSoup解析网页,通过 find 方法找到 article-main 对应的 div 块,在该 div 块下继续使用 find_all 方法搜寻全部的 img 标签,并提取其 src 属性对应的值,于是我们便获得了该文章下全部图片的 URL 列表。

接下来就是保存图片。

photo_url = "http://p3.pstatp.com/large/159f00010b30d6736512"

photo_name = photo_url.rsplit('/', 1)[-1] + '.jpg'

with request.urlopen(photo_url) as res, open(photo_name, 'wb') as f:

    f.write(res.read())

基本步骤就是这么多了,整理下爬取流程:

指定查询参数,向http://www.toutiao.com/search_content/提交我们的查询请求。

从返回的数据(JSON 格式)中解析出全部文章的 URL,分别向这些文章发送请求。

从返回的数据(HTML 格式)提取出文章的标题和全部图片链接。

再分别向这些图片链接发送请求,将返回的图片输入保存到本地(E:\jiepai)。

修改查询参数,以使服务器返回新的文章数据,继续第一步。


3、完整代码

import re

import json

import time

import random

from pathlib import Path

from urllib import parse

from urllib import error

from urllib import request

from datetime import datetime

from http.client import IncompleteRead

from socket import timeout as socket_timeout

from bs4 import BeautifulSoup

def _get_timestamp():

    """

    向 http://www.toutiao.com/search_content/ 发送的请求的参数包含一个时间戳,

    该函数获取当前时间戳,并格式化成头条接收的格式。格式为 datetime.today() 返回

    的值去掉小数点后取第一位到倒数第三位的数字。

    """

    row_timestamp = str(datetime.timestamp(datetime.today()))

    return row_timestamp.replace('.', '')[:-3]

def _create_dir(name):

    """

    根据传入的目录名创建一个目录,这里用到了 python3.4 引入的 pathlib 库。

    """

    directory = Path(name)

    if not directory.exists():

        directory.mkdir()

    return directory

def _get_query_string(data):

    """

    将查询参数编码为 url,例如:

    data = {

            'offset': offset,

            'format': 'json',

            'keyword': '街拍',

            'autoload': 'true',

            'count': 20,

            '_': 1480675595492

    }

    则返回的值为:

    ?offset=20&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&_=1480675595492"

    """

    return parse.urlencode(data)

def get_article_urls(req, timeout=10):

    with request.urlopen(req, timeout=timeout) as res:

        d = json.loads(res.read().decode()).get('data')

        if d is None:

            print("数据全部请求完毕...")

            return

        urls = [article.get('article_url') for article in d if article.get('article_url')]

        return urls

def get_photo_urls(req, timeout=10):

    with request.urlopen(req, timeout=timeout) as res:

        # 这里 decode 默认为 utf-8 编码,但返回的内容中含有部分非 utf-8 的内容,会导致解码失败

        # 所以我们使用 ignore 忽略这部分内容

        soup = BeautifulSoup(res.read().decode(errors='ignore'), 'html.parser')

        article_main = soup.find('div', id='article-main')

        if not article_main:

            print("无法定位到文章主体...")

            return

        heading = article_main.h1.string

        if '街拍' not in heading:

            print("这不是街拍的文章!!!")

            return

        img_list = [img.get('src') for img in article_main.find_all('img') if img.get('src')]

        return heading, img_list

def save_photo(photo_url, save_dir, timeout=10):

    photo_name = photo_url.rsplit('/', 1)[-1] + '.jpg'

    # 这是 pathlib 的特殊操作,其作用是将 save_dir 和 photo_name 拼成一个完整的路径。例如:

    # save_dir = 'E:\jiepai'

    # photo_name = '11125841455748.jpg'

    # 则 save_path = 'E:\jiepai\11125841455748.jpg'

    save_path = save_dir / photo_name

    with request.urlopen(photo_url, timeout=timeout) as res, save_path.open('wb') as f:

        f.write(res.read())

        print('已下载图片:{dir_name}/{photo_name},请求的 URL 为:{url}'

              .format(dir_name=dir_name, photo_name=photo_name, url=a_url))

if __name__ == '__main__':

    ongoing = True

    offset = 0  # 请求的偏移量,每次累加 20

    root_dir = _create_dir('E:\jiepai')  # 保存图片的根目录

    request_headers = {

        'Referer': 'http://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',

        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'

    }

    while ongoing:

        timestamp = _get_timestamp()

        query_data = {

            'offset': offset,

            'format': 'json',

            'keyword': '街拍',

            'autoload': 'true',

            'count': 20,  # 每次返回 20 篇文章

            '_': timestamp

        }

        query_url = 'http://www.toutiao.com/search_content/' + '?' + _get_query_string(query_data)

        article_req = request.Request(query_url, headers=request_headers)

        article_urls = get_article_urls(article_req)

        # 如果不再返回数据,说明全部数据已经请求完毕,跳出循环

        if article_urls is None:

            break

        # 开始向每篇文章发送请求

        for a_url in article_urls:

            # 请求文章时可能返回两个异常,一个是连接超时 socket_timeout,

            # 另一个是 HTTPError,例如页面不存在

            # 连接超时我们便休息一下,HTTPError 便直接跳过。

            try:

                photo_req = request.Request(a_url, headers=request_headers)

                photo_urls = get_photo_urls(photo_req)

                # 文章中没有图片?跳到下一篇文章

                if photo_urls is None:

                    continue

                article_heading, photo_urls = photo_urls

                # 这里使用文章的标题作为保存这篇文章全部图片的目录。

                # 过滤掉了标题中在 windows 下无法作为目录名的特殊字符。

                dir_name = re.sub(r'[\\/:*?"<>|]', '', article_heading)

                download_dir = _create_dir(root_dir / dir_name)

                # 开始下载文章中的图片

                for p_url in photo_urls:

                    # 由于图片数据以分段形式返回,在接收数据时可能抛出 IncompleteRead 异常

                    try:

                        save_photo(p_url, save_dir=download_dir)

                    except IncompleteRead as e:

                        print(e)

                        continue

            except socket_timeout:

                print("连接超时了,休息一下...")

                time.sleep(random.randint(15, 25))

                continue

            except error.HTTPError:

                continue

        # 一次请求处理完毕,将偏移量加 20,继续获取新的 20 篇文章。

        offset += 20


同理,只需修改代码,就可以下载想要的关键词,自己动手,想啥有啥。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容