网络爬虫天地

今日头条爬虫解析

2018-10-05  本文已影响0人  探索者_逗你玩儿

如今自媒体风生水起,很多人开始入住各大自媒体平台进行自媒体创作。想要持续的输出高质量的文章太难了,于是很多人就开始搞起了伪原创,拿别人比较热的文章过来改一改,不仅轻松还能收获一票粉丝,偏题了,我不是鼓励大家搞伪原创。今天我们的主题是爬虫,既然自媒体平台有这么多高质量的文章,想要一一收藏太难了,于是就想出了通过网络爬虫将感兴趣的文章爬取下来然后进行收藏,岂不是很爽,于是开始动手。今天拿今日头条练手。

第一步分析入口,今日头条的文章入口主要分为频道入口,搜索入口,用户主页入口,那么我们就一一开始破解。

首先从频道入口下手,分析网页结构,发现所有的文章都是通过ajax动态加载,那么第一想法是通过selenium模拟浏览器进行网页提取,虽然目的可以达到但是效果不理想,需要处理分页去重而且效率不高,故这个方案放弃,在接着进行分析ajax接口,貌似行得通,架起代码开始测试,在处理ajax接口是发现需要处理as,cp,_signature 三个参数,接口如下

https://www.toutiao.com/api/pc/feed/?category=news_tech&utm_source=toutiao&widen=1&max_behot_time=0&max_behot_time_tmp=0&tadrequire=true&as=A125AB7BC7F0F59&cp=5BB7802FF5896E1&_signature=NOFpxAAAb1yLl5gie2NwDTThad

as,cp网上已经有大神破解了算法如下;

    def getASCP(self):
        t = int(math.floor(time.time()))
        e = hex(t).upper()[2:]
        m = hashlib.md5()
        m.update(str(t).encode(encoding='utf-8'))
        i = m.hexdigest().upper()

        if len(e) != 8:
            AS = '479BB4B7254C150'
            CP = '7E0AC8874BB0985'
            return AS, CP

        n = i[0:5]
        a = i[-5:]
        s = ''
        r = ''
        for o in range(5):
            s += n[o] + e[o]
            r += e[o + 3] + a[o]

        AS = 'A1' + s + e[-3:]
        CP = e[0:3] + r + 'E1'
        return AS, CP

比较难搞的是signature参数,虽然网上也有很多人发文怎么破解,但是效果都不理想,只能拿到第一次请求的signature,第二次请求就直接不行了。分析js发现signature的请求是通过window.TAC.sign方法产生,而这个方法是动态绑定的,由一堆看不清逻辑的字符串通过一定的算法解密后得到,着手分析了一下,发现里面用到了Date ,Convas 相关的函数,姑且进行了一下推断,判断入参的时间戳跟当前的时间戳进行对比,肯定不能大于当前的时间,但是范围也不能相差太远否则一个频道页内容直接就爆了,对于Convas 可能就是为了限定上下文,否则为什么我们通过python直接执行TAC.sign方法产生的signature在第二次就会失效,虽说第一次能请求成功那么我们是不是每次都模拟第一次请求,虽说也能得到数据,但不能连续采集还是有点失望的。那有没有其他的办法可以解决了,在经过一下午的思考过后发现,既然在保证上下文的情况下可以连续采集(通过chrome的console生成的signature是可以的)那么我们通过selenium方案来模拟上下文,负责产生signature,剩下的就是通过urllib来请求接口获取数据进行解析是否可以行了?经过一番验证结果是可喜的,功夫不负有心人达到目的。直接贴代码。代码中有些自有逻辑没有贴出来,但是逻辑思路基本上都有了。今天到此为止,下次说怎么爬详情


    def get_channel_data(self, page):  #获取数据
        req = self.s.get(url=self.url, verify=False, proxies=get_proxy_ip())
        #print (self.s.headers)
        #print(req.text)
        headers = {'referer': self.url}
        max_behot_time='0'
        signature='.1.hXgAApDNVcKHe5jmqy.9f4U'
        eas = 'A1E56B6786B47FE'
        ecp = '5B7674A7FF2E9E1'
        self.s.headers.update(headers)
        item_list = []
        browser = webdriver.Chrome()
        browser.implicitly_wait(10)
        browser.get(self.url)
        for i in range(0, page):

            Honey = json.loads(self.get_js())
            # eas = self.getHoney(int(max_behot_time))[0]
            # ecp = self.getHoney(int(max_behot_time))[1]
            eas = Honey['as']
            ecp = Honey['cp']
            signature = Honey['_signature']
            if i > 0:
                signature = browser.execute_script("return window.TAC.sign("+ max_behot_time +")")
            url='https://www.toutiao.com/api/pc/feed/?category={}&utm_source=toutiao&widen=1&max_behot_time={}&max_behot_time_tmp={}&tadrequire=true&as={}&cp={}&_signature={}'.format(self.channel,max_behot_time,max_behot_time,eas,ecp,signature)
            req=self.s.get(url=url, verify=False, proxies=get_proxy_ip())
            time.sleep(random.random() * 2+2)
            # print(req.text)
            # print(url)
            j=json.loads(req.text)
            for k in range(0, 10):
                item = toutiaoitem()
                now=time.time()
                if j['data'][k]['tag'] != 'ad' or j['data'][k]['tag'] != 'ad.platform.site':
                    item.title = j['data'][k]['title']  ##标题
                    item.source = j['data'][k]['source']  ##作者
                    item.source_url = 'https://www.toutiao.com/'+j['data'][k]['source_url']   ##文章链接
                    item.media_url = 'https://www.toutiao.com/'+j['data'][k]['media_url']  #作者主页
                    item.article_genre = j['data'][k]['article_genre']  #文章类型
                    try:
                        item.comments_count = j['data'][k]['comments_count']  ###评论
                    except:
                        item.comments_count = 0

                    item.tag = j['data'][k]['tag']  ###频道名
                    try:
                        item.chinese_tag = j['data'][k]['chinese_tag']   ##频道中文名
                    except:
                        item.chinese_tag = ''
                    try:
                        item.label = j['data'][k]['label']  ## 标签
                    except:
                        item.label = []
                    try:
                        item.abstract = j['data'][k]['abstract']  ###文章摘要
                    except:
                        item.abstract = ''
                    behot = int(j['data'][k]['behot_time'])
                    item.behot_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(behot))  ####发布时间
                    item.collect_time = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(now))  ##抓取时间
                    item.item_id = j['data'][k]['item_id']
                    try:
                        item.image_list = j['data'][k]['image_list']
                    except:
                        item.image_list = []
                    item.image_url = j['data'][k]['image_url']
                    item.middle_image = j['data'][k]['middle_image']
                item_list.append(item)
            toutiaodb.save(item_list)
            time.sleep(2)
            max_behot_time = str(j['next']['max_behot_time'])
上一篇下一篇

猜你喜欢

热点阅读