前言

接到一个需求:爬包含关键字的推文。后来才告诉我转交给别人做了(摊手),那这里就分享一下如何爬取 twitter 数据。
结果我拖了两周才开始梳理 😂

Twitter API

推特提供了 Twitter API,可以用于查询推特数据,个人使用的话有以下两种:

  1. Twitter API v2
  2. Standard v1.1

当然还有高级版和企业版:

  1. Premium v1.1
  2. Enterprise

标准版仅支持搜索 7 天内的推特,其余都支持全搜索(从 2006.03 开始),官方给出了比较:Comparing Twitter API’s Search Tweets endpoints

使用标准版需要申请开发者账户Apply for a developer account,使用 v2 版本的需要申请 Academic Research product track。我试了申请开发者账户,然后妥妥地被拒绝了,有人说需要美国账户/手机号之类的信息,因为不想拿自用的推特瞎测试,也就罢了。

这里的目标是搜索特定时间范围内,包含特定关键词的 tweets(即,推文),因此就算申请到了也不能满足需求,转而寻求开源解决方案。

开源解决方案

搜索 GitHub 上爬取 twitter 数据的开源项目,筛选出以下 9 个试用(按 star 数量排列):

名称 star 最后一次更新 是否可用
twint 13k 2021.03.03
tweepy 8.7k 2022.04.22 ✔️(需要申请 Twitter API)
twitter-scraper 3.2k 2021.12.18
twitterscraper 2k 2020.07.28
Scweet 383 2022.03.23 ✔️
SearchTT 146 2020.06.04
Twitter Hashtag crawler 75 2020.12.16
stweet 99 2021.10.14 ✔️
Web_Scraping_Tweet_Traffic 6 2019.12.15

twint

不用 Twitter API 爬取推文,支持标签、趋势、敏感信息等搜索选项,也支持爬取用户信息,包括关注者、推文。

  1. 安装

    直接从 pypi 安装的包版本较低,需要升级

    1
    pip install --upgrade git+https://github.com/twintproject/twint.git@origin/master#egg=twint
  2. 示例

    配置一个代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import twint

    c = twint.Config()
    c.Proxy_host = '127.0.0.1'
    c.Proxy_port = '7890'
    c.Proxy_type = 'http'

    c.Store_csv = True
    c.Output = "tweets.csv"

    c.Limit = 10
    c.Custom_query = "nijisanji"

    twint.run.Search(c)

    然后挂掉

    1
    WARNING:root:Error retrieving https://twitter.com/: ConnectTimeout(MaxRetryError("HTTPSConnectionPool(host='twitter.com', port=443): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000001D2C5A295B0>, 'Connection to twitter.com timed out. (connect timeout=10)'))")), retrying

    翻了翻 issue 有人在二月份修复了:Fix the bug that proxy cannot be used when get token #1138,但没有合并。

    顺便发现有人提设置时间范围的 sinceuntil 失效了

  3. 总结

    自己试着修改或者等一个大更新,四百多的 issue 看来是没有太多的精力修啊😅

tweepy

实际上就是对 twitter API 的封装,不用从零手写请求和处理数据。

  1. 安装

    1
    pip install tweepy
  2. 示例

    没有申请到开发者账户,跳过!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import tweepy

    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)

    api = tweepy.API(auth)

    public_tweets = api.home_timeline()
    for tweet in public_tweets:
    print(tweet.text)
  3. 总结

    Twitter API v2 的支持还在开发中,申请到开发者账户的就用它吧!

twitter-scraper

支持标签、趋势等搜索选项,也支持用户信息的搜索。

  1. 安装

    1
    pip install twitter_scraper
  2. 示例

    因为没有提供设值代理的选项,所以直接在本地开全局模式代理

    1
    2
    3
    4
    from twitter_scraper import get_tweets

    for tweet in get_tweets('twitter'):
    print(tweet['text'])

    报错😅

    1
    requests.exceptions.ProxyError: HTTPSConnectionPool(host='twitter.com', port=443): Max retries exceeded with url: /i/profiles/show/twitter/timeline/tweets?include_available_features=1&include_entities=1&include_new_items_bar=true (Caused by ProxyError('Cannot connect to proxy.', OSError(0, 'Error')))

    改下源码,报错在 tweets.py 这个文件,添加代理

    1
    2
    3
    4
    5
    def get_tweets(query, pages=25):
    def gen_tweets(pages):
    proxy = 'http://127.0.0.1:7890'
    r = session.get(url, headers=headers, proxies={'http': proxy, 'https': proxy})
    ...

    重新执行,新的报错😅

    1
    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
  3. 总结

    作者说现在已经无法使用了(Does this work? #191),而且自己忙于工作暂时没时间更新(Doesn’t scrap anything. #189),暂且观望吧。

twitterscraper

所以为什么要起一样的名字?!

  1. 安装

    1
    pip install twitterscraper
  2. 示例

    直接上命令行了,但是无法访问默认代理 https://free-proxy-list.net

    1
    twitterscraper Trump --limit 1000 --output=tweets.json

    报错

    1
    requests.exceptions.ConnectionError: HTTPSConnectionPool(host='free-proxy-list.net', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x0000019FAE33BDC0>: Failed to establish a new connection: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。'))

    修改源码 query.py,直接返回本地代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def get_proxies():
    return ['127.0.0.1:7890']
    response = requests.get(PROXY_URL)
    soup = BeautifulSoup(response.text, 'lxml')
    table = soup.find('table',id='proxylisttable')
    list_tr = table.find_all('tr')
    list_td = [elem.find_all('td') for elem in list_tr]
    list_td = list(filter(None, list_td))
    list_ip = [elem[0].text for elem in list_td]
    list_ports = [elem[1].text for elem in list_td]
    list_proxies = [':'.join(elem) for elem in list(zip(list_ip, list_ports))]
    return list_proxies

    输出请求参数,然后报错…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    INFO:twitterscraper:queries: ['Trump since:2006-03-21 until:2006-12-30', 'Trump since:2006-12-30 until:2007-10-10', 'Trump since:2007-10-10 until:2008-07-20', 'Trump since:2008-07-20 until:2009-04-30', 'Trump since:2009-04-30 until:2010-02-08', 'Trump since:2010-02-08 until:2010-11-19', 'Trump since:2010-11-19 until:2011-08-31', 'Trump since:2011-08-31 until:2012-06-10', 'Trump since:2012-06-10 until:2013-03-21', 'Trump since:2013-03-21 until:2013-12-30', 'Trump since:2013-12-30 until:2014-10-10', 'Trump since:2014-10-10 until:2015-07-21', 'Trump since:2015-07-21 until:2016-04-30', 'Trump since:2016-04-30 until:2017-02-09', 'Trump since:2017-02-09 until:2017-11-20', 'Trump since:2017-11-20 until:2018-08-31', 'Trump since:2018-08-31 until:2019-06-11', 'Trump since:2019-06-11 until:2020-03-21', 'Trump since:2020-03-21 until:2020-12-30', 'Trump since:2020-12-30 until:2021-10-11']
    ConnectionError HTTPSConnectionPool(host='twitter.com', port=443): Max retries exceeded with url: /search?f=tweets&vertical=default&q=Trump%20since%3A2006-03-21%20until%3A2006-12-30&l=None (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000002975B91D430>: Failed to establish a new connection: [WinError 10060] 由于连接方在一段时间
    后没有正确答复或连接的主机没有反应,连接尝试失败。')) while requesting "https://twitter.com/search?f=tweets&vertical=defa
    ult&q=Trump%20since%3A2006-03-21%20until%3A2006-12-30&l=None"
    Traceback (most recent call last):
    File "C:\Users\linki\Desktop\t\lib\site-packages\urllib3\connection.py", line 174, in _new_conn
    conn = connection.create_connection(
    File "C:\Users\linki\Desktop\t\lib\site-packages\urllib3\util\connection.py", line 96, in create_connection
    raise err
    File "C:\Users\linki\Desktop\t\lib\site-packages\urllib3\util\connection.py", line 86, in create_connection
    sock.connect(sa)
    TimeoutError: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。
  3. 总结

    翻了翻 issue:没法用,等更新。

Scweet

支持关键词、标签、时间范围等搜索选项,也支持用户信息、关注、关注者的爬取。

  1. 安装

    1
    pip install Scweet==1.6
  2. 示例

    用 selenium 模拟浏览器访问,竟然还不是 headless 模式,直接给我弹出一个窗口可还行。注意这里不是本地时间,是 UTC 时间;存储格式为 UTF-8。

    1
    2
    3
    4
    5
    6
    from Scweet.scweet import scrape

    data = scrape(words=["nijisanji"], since="2020-01-01", until="2021-01-01", from_account=None,
    interval=1,
    headless=False, display_type="Latest", save_images=False, proxy="127.0.0.1:7890", save_dir='outputs',
    resume=False, filter_replies=True, proximity=False)

    结果爬了 175 条数据

  3. 总结

    可以用!暂时没遇到什么问题,用它!

SearchTT

还写了一篇知乎文章:这可能是是中文网上关于Twitter信息检索爬虫最全的项目了

描述含糊、仓库不更新、甚至还曾出租 API(评论里看起来可能是),拉倒🙃。

Twitter Hashtag crawler

根据标签(hashtag)搜索

  1. 安装

    1
    2
    3
    git clone https://github.com/amitupreti/Hands-on-WebScraping
    cd Hands-on-WebScraping/project1_twitter_hashtag_crawler
    pip install -r requirements.txt

    报错

    1
    2
    ERROR: Could not find a version that satisfies the requirement dateutil (from versions: none)
    ERROR: No matching distribution found for dateutil

    但是本地已经有了 dateutil

    1
    2
    3
    4
    pip install python-dateutil --upgrade
    # Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
    # Requirement already satisfied: python-dateutil in c:\users\linki\desktop\t\lib\site-packages (2.8.2)
    # Requirement already satisfied: six>=1.5 in c:\users\linki\desktop\t\lib\site-packages (from python-dateutil) (1.16.0)

    直接装个 scrapy 得了

    1
    2
    pip install scrapy
    pip install ipdb
  2. 示例

    没有给代理配置的入口,显然连不上

    1
    scrapy crawl twittercrawler -a filename=myhashtags.csv -o mydata.csv
  3. 总结

    能够自定义的配置项太少,而且仅针对标签搜索,跳过。

stweet

支持推特的高级搜索选项,同时支持推文和用户信息的爬取,stweet/docs/notebooks/ 目录下有各种示例

  1. 安装

    1
    pip install stweet
  2. 示例

    提供许多配置项,非常友好

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import arrow
    import stweet as st

    ProxyConfig = st.RequestsWebClientProxyConfig(
    http_proxy="127.0.0.1:7890",
    https_proxy="127.0.0.1:7890"
    )

    since = arrow.get('2021-10-01')
    until = arrow.get('2021-10-02')

    search_tweets_task = st.SearchTweetsTask(
    exact_words="nijisanji",
    since=since,
    until=until,
    replies_filter=st.RepliesFilter.ONLY_ORIGINAL,
    )

    st.TweetSearchRunner(
    search_tweets_task=search_tweets_task,
    tweet_outputs=[st.CsvTweetOutput('nijisanji_20211001_20211002.csv'), st.PrintTweetOutput()],
    web_client=st.RequestsWebClient(proxy=ProxyConfig, verify=False),
    ).run()

    不碍事儿的警告

    1
    2
    C:\Users\linki\Desktop\t\lib\site-packages\urllib3\connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host '127.0.0.1'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
    warnings.warn(

    添加以下语句关闭

    1
    2
    import urllib3
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    爬得非常快,字段也比 scweet 收集的多,但是只有 2021.10.02 的数据,难道时间范围是左开右闭的。多试几次发现爬太快了提示 远程主机强迫关闭了一个现有的连接,而且每次爬取的结果都不一样…

  3. 总结

    虽然能用但有点问题,作者正在准备 stweet 2.0,等推出之后再进行尝试。

  4. 更新

    2021.10.14 更新 stweet 2.0,说明文档还不够完善,如何使用的例子也没有。
    2021.10.15 测试了一下,可以爬取推文数据和用户数据否,但是现在只支持保存 JSON 格式的文件(因为没写解析),重复爬取了几次从文件大小上看都一样,所以应该没问题了。可以再等等完善。

Web_Scraping_Tweet_Traffic

配合文章食用:

该仓库已于 2019 年停更,可作为爬取思路的学习材料。

在线爬取

https://www.vicinitas.io/free-tools/download-search-tweets ,需要推特账户登陆后爬取,可以一试。