由于各种各样的原因,大家会有想要爬取twitter的用户的信息的想法,但申请官方api的那几篇小作文不是谁都能写得出的(本人就写不出),所以需要直接开始爬取内容,而爬twitter有时就是一个大坑。这里就讲讲本人处理Twitter Monitor期间遇过的坑。

Javascript文件

Twitter会在首页引入5个JavaScript文件,由于webpack打包的原因,它们的名字不一定与本文的相同,但可以提供参考,也为下文的说明提供参考

name link
polyfills https://abs.twimg.com/responsive-web/web/polyfills.321d1c14.js
vendors https://abs.twimg.com/responsive-web/web/vendors~main.483e4ab4.js
i18n-rweb/zh https://abs.twimg.com/responsive-web/web/i18n-rweb/zh.322c7be4.js
i18n-horizon/zh https://abs.twimg.com/responsive-web/web/i18n-horizon/zh.15b97c64.js
main https://abs.twimg.com/responsive-web/web/main.f18fcbb4.js

第3、4位的是语言文件

还有一些其他可能有用的文件

name link
bundle.UserProfile https://abs.twimg.com/responsive-web/web/bundle.UserProfile.e36cd9b4.js

鉴权

爬内容的api来来去去就是那几个,已经好几年没有更新过了,但是大多数人会遇到的第一个问题,那就是鉴权。举个例子

1
2
3
4
curl 'https://api.twitter.com/2/timeline/profile/783214.json?tweet_mode=extended&count=20' \
-H 'x-guest-token: 1232704521454999999' \
-H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' \
--compressed

上面是爬取一个用户推文时间线(timeline)的最低限度的请求,其中链接不需要多说都能理解,这里出现了x-guest-tokenauthorization。虽然这两个值看起来让人毫无头绪,其实都是可以自行取得的。

x-guest-token

x-guest-token 决定你的rate-limit,当此值为空或者不正确时twitter会返回如

1
2
3
4
5
6
7
8
{
"errors": [
{
"message": "Rate limit exceeded",
"code": 88
}
]
}

的错误,此值会在用户第一次访问twitter的时候在网页上赋予,所以直接构造一个请求

1
curl 'https://twitter.com' --compressed

此时得到的网页会有以下几行赋予x-guest-token

1
2
3
<script nonce="MDRjZmJlNWItYWNmOC00MTdiLWIxYjUtYTFhZTUyYTc2ODg4">
document.cookie = decodeURIComponent("gt=1232704521454999999; Max-Age=10800; Domain=.twitter.com; Path=/; Secure");
</script>

2020-06-24 更新:
上述方法已失效,twitter 已改为在 响应头(Response header) 赋予gt

1
set-cookie: gt=1232704521454999999; Max-Age=10200; Expires=Wed, 24 Jun 2020 08:31:03 GMT; Path=/; Domain=.twitter.com; Secure

2020-07-14 更新:
他们又改回来了

因此可以构建正则表达式 /gt=([0-9]+)/ 取得此值。

* 偶然在一条issue翻到一个1.1 版的 api,因为是旧版api,所以不知道什么时候失效

1
2
3
4
curl 'https://api.twitter.com/1.1/guest/activate.json' \
-X 'POST' \
-H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' \
--compressed

会返回

1
2
3
{
"guest_token": "1290584024826540032"
}

method 要使用 POST ,用 GET 会返回

1
2
3
4
5
6
{
"errors": [{
"code": 86,
"message": "This method requires a POST."
}]
}

authorization

1
AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA

这没什么好说的,此值固定,出现在 https://abs.twimg.com/responsive-web/web/main.f18fcbb4.js ,即使未来twitter更新了前端也会出现在类似文件名称的js文件中。

1
<link rel="preload" as="script" crossorigin="anonymous" href="https://abs.twimg.com/responsive-web/web/main.f18fcbb4.js" nonce="OGE1NzNmZTQtNzQxMS00Y2FiLTllYTItMDFlNGZlNTM1ZDFh" />

差不多是这样的。


rate-limit

rate-limit 限制了用户在一定时间内请求的次数,并且会在相对时间后重置,在twitter,这个时间是15分钟。

根据上文我们可以知道twitter是通过x-guest-token判断rate-limit的,在用户的每次请求所返回的header上都会有以下内容

1
2
3
x-rate-limit-limit: 180
x-rate-limit-remaining: 179
x-rate-limit-reset: 1567401449

很好理解对吧,https://api.twitter.com/1.1/application/rate_limit_status.json 这个文件详细说明了各个api的rate-limit。

不要以为你刷新了 guest-token 就不会受到限制,那只是说明你的请求还不够多


用户信息

爬取用户信息很轻松,这里有几个接口

  • 第一次加载用户信息时使用

    1
    2
    3
    4
    curl 'https://api.twitter.com/graphql/P8ph10GzBbdMqWZxulqCfA/UserByScreenName?variables=%7B%22screen_name%22%3A%22twitter%22%2C%22withHighlightedLabel%22%3Afalse%7D' \
    -H 'x-guest-token: 1232704521454999999' \
    -H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' \
    --compressed

    其中P8ph10GzBbdMqWZxulqCfA出现在前文提到的那个main开头名称的js文件内,此值是否固定未知,故不推荐

    1
    2
    3
    4
    5
    {
    queryId: "P8ph10GzBbdMqWZxulqCfA",
    operationName: "UserByScreenName",
    operationType: "query"
    }

    此处的变量是urlencode化的json

    1
    2
    3
    4
    {
    "screen_name": "twitter",
    "withHighlightedLabel": false
    }
    • Twitter 为联合国五大常任理事国(中美俄法英,排名不分先后)的 政府机构(小旗子)和 官方媒体(小讲台)的帐号(不包括个人)分别添加了标记,此类信息藏身于 data.user.affiliates_highlighted_label.label 节点,其中,来自中国的帐号不包括港澳台的官方机构,且对应的跳转链接对应的内容比其他版本的开头多了一段话,一般版本见文章末尾的参考网页

      下面是新华社的信息节选

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      {
      "affiliates_highlighted_label": {
      "label": {
      "url": {
      "url_type": "DeepLink",
      "url": "https://help.twitter.com/rules-and-policies/state-affiliated-china"
      },
      "badge": {
      "url": "https://pbs.twimg.com/semantic_core_img/1290398851254247424/qxZbv2Fr?format=png&name=orig"
      },
      "description": "China state-affiliated media"
      }
      }
      }
  • 刷新时间线时使用

    1
    2
    3
    4
    curl 'https://api.twitter.com/1.1/users/show.json?include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&skip_status=1&screen_name=twitter' \
    -H 'x-guest-token: 1232704521454999999' \
    -H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' \
    --compressed
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    include_profile_interstitial_type: 1
    include_blocking: 1
    include_blocked_by: 1
    include_followed_by: 1
    include_want_retweets: 1
    include_mute_edge: 1
    include_can_dm: 1
    include_can_media_tag: 1
    skip_status: 1
    user_id: 783214
    screen_name: twitter

    其中,user_idscreen_name需要二选一即可。

    返回的数据大同小异,在以后都以第二种形式返回的为参考

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    {
    "id": 783214,
    "id_str": "783214",
    "name": "Twitter",
    "screen_name": "Twitter",
    "location": "Everywhere",
    "profile_location": null,
    "description": "What\u2019s happening?!",
    "url": "https:\/\/t.co\/TAXQpsHa5X",
    "entities": {
    "url": {
    "urls": [
    {
    "url": "https:\/\/t.co\/TAXQpsHa5X",
    "expanded_url": "https:\/\/about.twitter.com\/",
    "display_url": "about.twitter.com",
    "indices": [0,23]
    }
    ]
    },
    "description": {
    "urls":[]
    }
    },
    "protected": false,
    "followers_count": 57276889,
    "fast_followers_count": 7785,
    "normal_followers_count": 57269104,
    "friends_count": 28,
    "listed_count": 90682,
    "created_at": "Tue Feb 20 14:35:54 +0000 2007",
    "favourites_count": 6404,
    "utc_offset": null,
    "time_zone": null,
    "geo_enabled": true,
    "verified": true,
    "statuses_count": 13096,
    "media_count": 1993,
    "lang": null,
    "contributors_enabled": false,
    "is_translator": false,
    "is_translation_enabled": false,
    "profile_background_color": "ACDED6",
    "profile_background_image_url": "http:\/\/abs.twimg.com\/images\/themes\/theme18\/bg.gif",
    "profile_background_image_url_https": "https:\/\/abs.twimg.com\/images\/themes\/theme18\/bg.gif",
    "profile_background_tile": true,
    "profile_image_url": "http:\/\/pbs.twimg.com\/profile_images\/1111729635610382336\/_65QFl7B_normal.png",
    "profile_image_url_https": "https:\/\/pbs.twimg.com\/profile_images\/1111729635610382336\/_65QFl7B_normal.png",
    "profile_banner_url": "https:\/\/pbs.twimg.com\/profile_banners\/783214\/1556918042",
    "profile_link_color": "1B95E0",
    "profile_sidebar_border_color": "FFFFFF",
    "profile_sidebar_fill_color": "F6F6F6",
    "profile_text_color": "333333",
    "profile_use_background_image": true,
    "has_extended_profile": true,
    "default_profile": false,
    "default_profile_image": false,
    "pinned_tweet_ids": [],
    "pinned_tweet_ids_str": [],
    "has_custom_timelines": true,
    "can_dm": false,
    "can_media_tag": true,
    "following": false,
    "follow_request_sent": false,
    "notifications": false,
    "muting": false,
    "blocking": false,
    "blocked_by": false,
    "want_retweets": false,
    "advertiser_account_type": "promotable_user",
    "advertiser_account_service_levels": [
    "media_studio",
    "dso",
    "analytics",
    "dso",
    "dso"
    ],
    "profile_interstitial_type": "",
    "business_profile_state": "none",
    "translator_type": "regular",
    "followed_by": false,
    "require_some_consent": false
    }

    有几点比较有意思

    • entities 中不含hashtag的信息,所以我也不知道它使用什么骚套路实现的

    • 用户的的背景图的格式是https://pbs.twimg.com/profile_banners/:userid/:bannerid,所以保存的时候其实可以把它拆开到使用的时候再组装……

    • profile_interstitial_type是一个很有意思的字段,它留空代表正常用户,其他都会得到twitter的警告,以下有对应警告,仅供参考

    注:此表格内容来自bundle.UserProfile

    value message
    fake_account 警告:此账号暂时受限。
    你看到这则警告,因为该账号有异常活动。是否仍要查看?
    sensitive_media 警告:此个人资料可能包含敏感内容。
    你看到这则警告,因为其中涉嫌使用不良图片或语言。是否仍要查看?

    注:这种警告经常在各种NSFW号上出现,为了找例子本人心灵受到了莫大的震撼
    1
    2
    3
    4
    5
    6
    {
    FakeAccount: "fake_account",
    OffensiveProfileContent: "offensive_profile_content",//What this is?
    SensitiveMedia: "sensitive_media",
    Timeout: "timeout"
    }
    • 用户有几种状态

      • 锁推:好吧这是我的说法,官方的说法叫做“保护”,被保护的帐号的帐号信息的protect字段为true,访问被保护的用户的页面会显示

        1
        2
        这些推文受到保护
        只有经过批准的关注者才可查看 @baristabar 的推文。若要申请访问,点击关注。
      • 删号或账号不存在

        • 帐号不存在:请求用户信息会返回

          1
          2
          3
          4
          5
          6
          7
          8
          {
          "errors": [
          {
          "code": 50,
          "message": "User not found."
          }
          ]
          }
        • 自删:即自己删号,这只是一种相对的说法,因为直接请求此用户的信息所返回的内容同上条,但若要修改用户名(screen_name)到该自删帐号的用户最后的用户名会被提示该用户名已被占用。请另选一个。

      • 被冻结:顾名思义,就是被封了

        1
        2
        3
        4
        5
        6
        7
        8
        {
        "errors": [
        {
        "code": 63,
        "message": "User has been suspended."
        }
        ]
        }
    • 因为Twitter有一个non_username_paths,顾名思义,就是不可做为用户名的目录,即便如此,那个列表并不是一定可靠的,因为即使需要用户名在列表上也是可以买的……下面列一个这个列表的现状,全表请参阅参考网页。(2020-3-8 0:44 UTC+8)

      用户名 返回代码 返回信息/全名 备注
      accounts 63 User has been suspended.
      all 0 ALL - Accor Live Limitless 认证用户
      anywhere 0 Anywhere 一般用户
      blog 0 steve 跳转 https://blog.twitter.com/
      business 0 Bloomberg 认证用户
      faq 0 Th\ufffderry Twitter FAQ页面
      followers 63 User has been suspended.
      friends 0 Friends 一般用户
      home 0 Geneia@home 登录用户显示用户时间线,未登录用户跳转登录界面
      jobs 63 User has been suspended.
      list 0 ya 认证用户
      logout 0 Waterfall 登录用户显示登出确认,未登录用户跳转登录界面
      me 0 Maine.com 一般用户
      retweets 0 All the crap I get on Whatsapp 一般用户
      sent 0 Sent 一般用户
      settings 0 Settings 用户设置
      signup 0 Feanamacatangay 跳转到 https://twitter.com/i/flow/signup
      signin 0 Signin 一般用户
      terms 0 Terms 页面不存在
      tos 63 User has been suspended.
      twttr 0 - 已锁
      welcome 63 User has been suspended.

推文内容

时间线(Timeline)

针对单个用户的时间线还是相对很简单的,只需要如同上面请求个人资料一样请求api接口,比如下面这个请求 twitter官方 的最近时间线的例子

1
2
3
4
curl 'https://api.twitter.com/2/timeline/profile/783214.json?tweet_mode=extended' \
-H 'x-guest-token: 1232704521454999999' \
-H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' \
--compressed

*twitter 网页的请求如下,注意三个变量uid, count, cursor

1
"https://api.twitter.com/2/timeline/profile/${uid}.json?include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&skip_status=1&cards_platform=Web-12&include_cards=1&include_composer_source=true&include_ext_alt_text=true&include_reply_count=1&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_color=true&include_ext_media_availability=true&send_error_codes=true&simple_quoted_tweets=true&ext=mediaStats%2CcameraMoment&count=${count}&cursor=${cursor}"

然后就能得到一个巨大的json,当初我花了点时间用来阅读整个json理清结构,理清结构以后事情就比较简单了
这里只提一些比较常用的项目,剩下的需要自行翻找

tweets

这里以 tweet id 为键名,键值的内容一目了然,所以只提以下几点

  • 这里包含了这一段用户时间线中出现过的所有推文,包括但不限于此用户发推(tweet)转推(retweet) 以及 引用(quote)

  • 引用(quote) 有时候会因为各种奇奇怪怪的原因导致显示 这条推文不可用。,但原推并没有被删,引用我在Twitter Monitor的注释

    //推文不可用不等于原推被删, 虽然真正的原因是什么我只能说我也不知道
    //群友说可能是被屏蔽了, 仅供参考

  • 我翻过网站爬取的内容,只找出五种 entities 类型,分别是

    名称 描述
    symbols 这个貌似是根据上市代码搜索相关公司的推文,例如 Twitter$TWTR ,官方管这玩意作cashtag, 个人感觉除了把#换成$以外并没有什么区别
    hashtags hashtag,顾名思义,主题标签,话题标签,平时会出现在侧边的 有什么新鲜事? ,其中有一些标签会带有小图标,那些是活动图标,官方称之为 Hashflags
    urls 链接,有原始链接和t.co短链接
    user_mentions @的形式提及的用户名
    media 媒体信息,后面会详细提及
  • 置顶推文会反反复复地出现在最新内容中,要注意去重

  • 更新的参数 cursor 藏得很深,初次处理会找得很头疼,一般出现在倒数第二项(凡事没绝对,为了靠谱我扔了个foreach去处理),路径参考下图左下角

    其实这里有一张图

  • 根据 About public-interest exceptions on Twitter ,一些可能违反twitter规则但可能有利于公众利益的推文不会被删,但twitter会在此推文上加注一段告示,并且会限制对该推文的互动,最近的经典例子就是 Donald J. Trump 关于 在明尼苏达州发生的事件 的发言

Cards

卡片很麻烦,各种意义上的麻烦,不容易发,也不容易找,找不到是很正常的事,总之就很让人头疼

在twitter首页可以找到以下一段json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"responsive_web_unified_cards_all_cards_enabled":{"value":false},
"responsive_web_unified_cards_amplify_enabled":{"value":true},
"responsive_web_unified_cards_app_enabled":{"value":true},
"responsive_web_unified_cards_appplayer_enabled":{"value":true},
"responsive_web_unified_cards_audio_enabled":{"value":true},
"responsive_web_unified_cards_broadcast_enabled":{"value":true},
"responsive_web_unified_cards_direct_store_link_app_enabled":{"value":true},
"responsive_web_unified_cards_image_direct_message_enabled":{"value":true},
"responsive_web_unified_cards_live_event_enabled":{"value":false},
"responsive_web_unified_cards_message_me_enabled":{"value":true},
"responsive_web_unified_cards_moment_enabled":{"value":true},
"responsive_web_unified_cards_periscope_broadcast_enabled":{"value":true},
"responsive_web_unified_cards_player_enabled":{"value":true},
"responsive_web_unified_cards_poll2choice_image_enabled":{"value":false},
"responsive_web_unified_cards_poll2choice_text_only_enabled":{"value":true},
"responsive_web_unified_cards_poll2choice_video_enabled":{"value":false},
"responsive_web_unified_cards_poll3choice_image_enabled":{"value":false},
"responsive_web_unified_cards_poll3choice_text_only_enabled":{"value":true},
"responsive_web_unified_cards_poll3choice_video_enabled":{"value":false},
"responsive_web_unified_cards_poll4choice_image_enabled":{"value":false},
"responsive_web_unified_cards_poll4choice_text_only_enabled":{"value":true},
"responsive_web_unified_cards_poll4choice_video_enabled":{"value":false},
"responsive_web_unified_cards_promo_image_app_enabled":{"value":true},
"responsive_web_unified_cards_promo_image_convo_enabled":{"value":true},
"responsive_web_unified_cards_promo_video_convo_enabled":{"value":true},
"responsive_web_unified_cards_promo_video_website_enabled":{"value":true},
"responsive_web_unified_cards_promo_website_enabled":{"value":true},
"responsive_web_unified_cards_promoted_cards_enabled":{"value":true},
"responsive_web_unified_cards_summary_enabled":{"value":true},
"responsive_web_unified_cards_summary_large_image_enabled":{"value":true},
"responsive_web_unified_cards_unified_card_enabled":{"value":true},
"responsive_web_unified_cards_video_direct_message_enabled":{"value":true},
"responsive_web_unified_cards_vine_enabled":{"value":true}
}

可以看到,大多数的卡片形式都是已经支持了,但实际上一般用户能发送出来的卡片只有少数几种,剩下的需要用 Twitter for Advertisers 或者其他未知的形式发送。

我已经找出了22种卡片的例子(投票型的只有一个),存放在 /docs/cards.json ,要利用twitter的搜索引擎寻找更多的卡片可以参考 igorbrigadir/twitter-advanced-search,讲得还挺详细的。

有些类型的卡片的图会随着网页的改版而更新,有必要的时候需要再跑一轮更新这些信息;至于投票型的卡片,第一次看到的时候我是震惊的,区分每个选项用的是 choice1_labelchoice2_label……习惯了就好了(写小作文那边的api倒是很舒服https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object

下面是一些没什么用的其他知识

  • periscope_broadcastsummary_large_image 结构相似,虽然它的UI与 broadcast 相似;结构的相似的还有 audiopromo_video_websiteplayerdirect_store_link_appapp
  • promo_image_convopromo_video_convo 都是提供了几个 hashtag 用以发推,发推后可见另一张图片和另一段信息
  • promo_image_app 是未登录时提供的卡片类型,点击下面的 安装 按钮时会跳到 Twitter 首页是它的特性,同一条推文在用户登录以后会使用 unified_card,此时提供了正确的链接和更完整的信息,比如这个例子
  • 卡片的 url 字段提供的信息是混乱的,不过一般可以回到同一条推的 entitiesurls 找到最后一条

unified_card

美好的一天从 Twitter Monitor 报警结束

因为 Twitter Monitor 已经能够处理大多数常见的卡片了,对于它还能找到新卡片还是没想到的,前往 Twitter 瞄了一眼,发现这玩意不是跟 summary_large_image 一个样嘛,想着花个几分钟处理一下就完事了,直到后来我才发现这玩意比我想象要复杂。

是的,单个组件的 unified_card 确实跟 summary_large_image 外观相似,然而根据它的名字就知道它可以拥有多个媒体块(图片、视频,类似走马灯),粗略寻找了一番就能发现(我不知道找全没有,暂时也没法把工作重心放在这里),

  • image_website
  • video_website
  • image_app
  • image_carousel_website
  • image_carousel_app
  • video_carousel_website

其中,后三种会有多个媒体使用 swipeable_media 组件,说白了就是走马灯,其余部分与普通卡片无异。

Twitter Monitor 监控首次报警是 2020-10-16 https://twitter.com/i/status/1316889033583149057,说明可能是为了逐步淘汰掉旧版的花样繁多的卡片,对于前端的处理来说是一件化繁为简的好事,对于爬虫来说……积攒下一百多条报警真有意思……

Image

处理图片真麻烦,以后我都不想碰它

除掉让人头疼的部分,图片还是挺有意思的,一张图片上传twitter以后会被压缩成各种大小,有时还会进行切割,抽出占比最大的五种颜色(不足五种就处理所有颜色)并记录rgb和占比,这些颜色进行处理后会成为图片未加载时图片框和大图浏览模式时模糊前的背景色(什么算法?这还真问到我了)

在 Twitter ,现在基本只会出现三种媒体文件格式:jpgpngmp4,其中,上传的 gif 格式的图片会被转换成 mp4,图片的大小有五种类型:large|medium|small|thumb|tiny|orig,我太久没处理这部分的问题了,我只记得移动端节流的时候使用的是 tiny ,大图浏览使用的是 large,其余的可能是为了适应各种分辨率吧,记不清了

图片的链接与两种格式 Legacy formatModern format

1
2
3
4
5
6
7
8
9
10
Legacy format
<base_url>.<format>:<name>
For example:
https://pbs.twimg.com/media/DOhM30VVwAEpIHq.jpg:large

Modern format
The modern format for loading photos was established at Twitter in 2015 and has been defacto since 2017. All photo media loads should move to this format.
<base_url>?format=<format>&name=<name>
For example:
https://pbs.twimg.com/media/DOhM30VVwAEpIHq?format=jpg&name=large

看完就懂,上面的带媒体卡片是没有 Legacy format 的,只能用 Modern format,其他信息可以参考 entities-object

* 我在 Twitter Monitor 是直接用 PHP 的curl组件输出来做代理的,这样做会导致 mp4 的进度条无法拖动,只需要提前获取 Content-Length 就能解决问题

// TODO
//我会在这里存放一些没来得及整理的内容

参考网页

评论