代码之家  ›  专栏  ›  技术社区  ›  HJA24

从Tweepy流式API输出过滤垃圾邮件推文

  •  0
  • HJA24  · 技术社区  · 7 年前

    我有下面的脚本,收集所有包含搜索词的tweets $BTC 或 $埃斯

    import sys
    import time
    import json
    import pandas as pd
    from tweepy import OAuthHandler
    from tweepy import Stream
    from tweepy.streaming import StreamListener
    
    USER_KEY = ''
    USER_SECRET = ''
    ACCESS_TOKEN = ''
    ACCESS_SECRET = ''
    
    class StdOutListener(StreamListener):
    
    def on_data(self, data):
       tweet = json.loads(data)
       print(tweet)
    
    
    def on_error(self, status):
       print(status)    
       return False
    
    if __name__ == "__main__":
    listener =  StdOutListener()
    auth = OAuthHandler(USER_KEY, USER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    stream = Stream(auth, l)
    stream.filter(languages=['en'], track=['$BTC', '$ETH'], async=True)
    

    问题是输出中有很多垃圾邮件。例如:

    enter image description here

    理想情况下,我想过滤掉垃圾邮件。所以我检查了这类tweets的JSON输出。

    {
     'created_at': 'Fri Oct 05 07:09:19 +0000 2018',
     'id': 1048107851829452800,
     'id_str': '1048107851829452800',
     'text': 'Current $ARK price: $0.69 \n\nWe checked! Binance registration is 
      currently open 🙌 😍  \n\n➡️ url_that_is_forbidden_by_stack_overflow… 
      url_that_is_forbidden_by_stack_overflow',
     'display_text_range': [
       0,
       140
      ],
     'source': '<a href="http://www.google.com" 
      rel="nofollow">medicinetoletitwin</a>',
     'truncated': True,
     'in_reply_to_status_id': None,
     'in_reply_to_status_id_str': None,
     'in_reply_to_user_id': None,
     'in_reply_to_user_id_str': None,
     'in_reply_to_screen_name': None,
     'user': {
      'id': 937395812748820480,
      'id_str': '937395812748820480',
      'name': 'Brenna 💰',
      'screen_name': 'BrennaPham',
      'location': 'San Jose, CA',
      'url': url_that_is_forbidden_by_stack_overflow,
      'description': 'Gamer ~',
      'translator_type': 'none',
      'protected': False,
      'verified': False,
      'followers_count': 168,
      'friends_count': 22,
      'listed_count': 2,
      'favourites_count': 17,
      'statuses_count': 12620,
      'created_at': 'Sun Dec 03 18:59:12 +0000 2017',
      'utc_offset': None,
      'time_zone': None,
      'geo_enabled': False,
      'lang': 'en',
      'contributors_enabled': False,
      'is_translator': False,
      'profile_background_color': 'F5F8FA',
      'profile_background_image_url': '',
      'profile_background_image_url_https': '',
      'profile_background_tile': False,
      'profile_link_color': '1DA1F2',
      'profile_sidebar_border_color': 'C0DEED',
      'profile_sidebar_fill_color': 'DDEEF6',
      'profile_text_color': '333333',
      'profile_use_background_image': True,
      'profile_image_url': 
      'http://pbs.twimg.com/profile_images/939260582460506112/oltTD- 
       f1_normal.jpg',
      'profile_image_url_https': 
      'https://pbs.twimg.com/profile_images/939260582460506112/oltTD- 
       f1_normal.jpg',
      'default_profile': True,
      'default_profile_image': False,
      'following': None,
      'follow_request_sent': None,
      'notifications': None
       },
     'geo': None,
     'coordinates': None,
     'place': None,
     'contributors': None,
     'is_quote_status': False,
     'extended_tweet': {
      'full_text': 'Current $ARK price: $0.69 \n\nWe checked! Binance 
       registration is currently open 🙌 😍  \n\n➡️ 
       url_that_is_forbidden_by_stack_overflow\n\n$EOS $BCAP $RMC $TIME $RCN $XVC $PBL $BTC $WGR 
       $FLIXX $BTG $BCD $SMT $UKG $XWC $XEM $CRB $PASC $KMD $VIU $BNB $YOYOW 
       $INFX url_that_is_forbidden_by_stack_overflow',
      'display_text_range': [
       0,
       236
       ],
     'entities': {
      'hashtags': [],
      'urls': [
        {
          'url': 'url_that_is_forbidden_by_stack_overflow',
          'expanded_url': 'http://binance.com/?ref=10078236',
          'display_url': 'binance.com/?ref=10078236',
          'indices': [
            89,
            112
          ]
        }
      ],
      'user_mentions': [],
      'symbols': [
        {
          'text': 'ARK',
          'indices': [
            8,
            12
          ]
        },
        {
          'text': 'EOS',
          'indices': [
            114,
            118
          ]
        },
        {
          'text': 'BCAP',
          'indices': [
            119,
            124
          ]
        },
        {
          'text': 'RMC',
          'indices': [
            125,
            129
          ]
        },
        {
          'text': 'TIME',
          'indices': [
            130,
            135
          ]
        },
        {
          'text': 'RCN',
          'indices': [
            136,
            140
          ]
        },
        {
          'text': 'XVC',
          'indices': [
            141,
            145
          ]
        },
        {
          'text': 'PBL',
          'indices': [
            146,
            150
          ]
        },
        {
          'text': 'BTC',
          'indices': [
            151,
            155
          ]
        },
        {
          'text': 'WGR',
          'indices': [
            156,
            160
          ]
        },
        {
          'text': 'FLIXX',
          'indices': [
            161,
            167
          ]
        },
        {
          'text': 'BTG',
          'indices': [
            168,
            172
          ]
        },
        {
          'text': 'BCD',
          'indices': [
            173,
            177
          ]
        },
        {
          'text': 'SMT',
          'indices': [
            178,
            182
          ]
        },
        {
          'text': 'UKG',
          'indices': [
            183,
            187
          ]
        },
        {
          'text': 'XWC',
          'indices': [
            188,
            192
          ]
        },
        {
          'text': 'XEM',
          'indices': [
            193,
            197
          ]
        },
        {
          'text': 'CRB',
          'indices': [
            198,
            202
          ]
        },
        {
          'text': 'PASC',
          'indices': [
            203,
            208
          ]
        },
        {
          'text': 'KMD',
          'indices': [
            209,
            213
          ]
        },
        {
          'text': 'VIU',
          'indices': [
            214,
            218
          ]
        },
        {
          'text': 'BNB',
          'indices': [
            219,
            223
          ]
        },
        {
          'text': 'YOYOW',
          'indices': [
            224,
            230
          ]
        },
        {
          'text': 'INFX',
          'indices': [
            231,
            236
          ]
        }
      ],
      'media': [
        {
          'id': 1048107850399137792,
          'id_str': '1048107850399137792',
          'indices': [
            237,
            260
          ],
          'media_url': 'http://pbs.twimg.com/media/DougiW1WwAA_8PZ.jpg',
          'media_url_https': 'https://pbs.twimg.com/media/DougiW1WwAA_8PZ.jpg',
          'url': 'url_that_is_forbidden_by_stack_overflow',
          'display_url': 'pic.twitter.com/2Y1evrvz3x',
          'expanded_url': 'https://twitter.com/BrennaPham/status/1048107851829452800/photo/1',
          'type': 'photo',
          'sizes': {
            'thumb': {
              'w': 150,
              'h': 150,
              'resize': 'crop'
            },
            'large': {
              'w': 1920,
              'h': 1080,
              'resize': 'fit'
            },
            'medium': {
              'w': 1200,
              'h': 675,
              'resize': 'fit'
            },
            'small': {
              'w': 680,
              'h': 383,
              'resize': 'fit'
            }
          }
        }
      ]
    },
    'extended_entities': {
      'media': [
        {
          'id': 1048107850399137792,
          'id_str': '1048107850399137792',
          'indices': [
            237,
            260
          ],
          'media_url': 'http://pbs.twimg.com/media/DougiW1WwAA_8PZ.jpg',
          'media_url_https': 'https://pbs.twimg.com/media/DougiW1WwAA_8PZ.jpg',
          'url': url_that_is_forbidden_by_stack_overflow,
          'display_url': 'pic.twitter.com/2Y1evrvz3x',
          'expanded_url': 'https://twitter.com/BrennaPham/status/1048107851829452800/photo/1',
          'type': 'photo',
          'sizes': {
            'thumb': {
              'w': 150,
              'h': 150,
              'resize': 'crop'
            },
            'large': {
              'w': 1920,
              'h': 1080,
              'resize': 'fit'
            },
            'medium': {
              'w': 1200,
              'h': 675,
              'resize': 'fit'
            },
            'small': {
              'w': 680,
              'h': 383,
              'resize': 'fit'
            }
          }
        }
      ]
    }
     },
    'quote_count': 0,
    'reply_count': 0,
    'retweet_count': 0,
    'favorite_count': 0,
    'entities': {
     'hashtags': [],
     'urls': [
      {
        'url': 'url_that_is_forbidden_by_stack_overflow',
        'expanded_url': 'http://binance.com/?ref=10078236',
        'display_url': 'binance.com/?ref=10078236',
        'indices': [
          89,
          112
        ]
      },
      {
        'url': 'url_that_is_forbidden_by_stack_overflow',
        'expanded_url': 'https://twitter.com/i/web/status/1048107851829452800',
        'display_url': 'twitter.com/i/web/status/1…',
        'indices': [
          114,
          137
        ]
      }
     ],
     'user_mentions': [],
     'symbols': [
      {
        'text': 'ARK',
        'indices': [
          8,
          12
        ]
      }
     ]
    },
    'favorited': False,
    'retweeted': False,
    'possibly_sensitive': False,
    'filter_level': 'low',
    'lang': 'en',
    'timestamp_ms': '1538723359435'
    

    我确定了以下将推特归类为垃圾邮件的标准:

    • 推特[好友计数]<50
    • 推特[关注者计数]>50
    • tweet['entities']['url']['display_url']包含指向特定垃圾邮件网站的链接

    因此,我在脚本中编写了一个新函数: 导入系统 导入时间 导入json 导入熊猫作为pd 从tweepy导入OAuthHandler 从tweepy导入流

    USER_KEY = ''
    USER_SECRET = ''
    ACCESS_TOKEN = ''
    ACCESS_SECRET = ''
    spam = ['spam_website_1', spam_website_2', 'spam_website_3']
    
    class StdOutListener(StreamListener):
    
    def on_data(self, data):
       tweet = json.loads(data)
       self.filter_tweet(tweet)
    
    
    def filter_tweet(self, tweet):
        url = data['entities']['urls']['display_url'] if 'display_url' in 
        data['entities']['urls'] else None
        if len(url) != 0):
           if data['user']['friends_count'] < 50:
              if data['user']['followers_count'] < 50:
                  if any(x in url for x in spam):
                    pass
        else:
           print(tweet)
    
    def on_error(self, status):
       print(status)    
       return False
    
    if __name__ == "__main__":
    listener =  StdOutListener()
    auth = OAuthHandler(USER_KEY, USER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    stream = Stream(auth, l)
    stream.filter(languages=['en'], track=['$BTC', '$ETH'], async=True)
    

    我想知道这个部分对于流式API输出是否足够快,或者应该重写。有可能写得更优雅更快吗?

     if len(url) != 0):
           if data['user']['friends_count'] < 50:
              if data['user']['followers_count'] < 50:
                  if any(x in url for x in spam):
                    pass
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   JeffProd    7 年前

    作为评论,你写道 tweet['followers_count'] > 50 然后 data['user']['followers_count'] < 50 在密码里。

    过滤垃圾邮件是一项艰巨的工作,我想即使是Twitter也无法解决这个问题。 我不认为这是一个关于追随者或朋友计数的问题。 即使你写了一份诈骗和垃圾邮件网站的黑名单,它每天都会改变。 或许你也可以列个黑名单。

    据我所知, if 测试很快(我有一些象棋编程的经验)。所以,是的,你可以边看边流。 但是,如果您的测试将增长,那么您可以直接推送tweets而无需任何处理,例如在Redis中。然后另一个脚本(worker)可以完成从redis发出tweets并进行垃圾邮件测试的工作。

    编辑:垃圾邮件标准的另一个想法:每天发布的推文数量。你举的用户为例,每天发布近42条推文。所以测试可以是 if tweetsPerDay > 10: spam . (我用在和现在的日期创建的用户帐户得到这个计数,转换成天,总tweets计数,然后计算平均值)。但它可能不太准确,比如检查追随者和朋友的数量。