Python爬取知乎与我所理解的爬虫与反爬虫

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python爬取知乎与我所理解的爬虫与反爬虫相关的知识,希望对你有一定的参考价值。

参考技术A

关于知乎验证码登陆的问题,用到了Python上一个重要的图片处理库PIL,如果不行,就把图片存到本地,手动输入。

通过对知乎登陆是的抓包,可以发现登陆知乎,需要post三个参数,一个是账号,一个是密码,一个是xrsf。
这个xrsf隐藏在表单里面,每次登陆的时候,应该是服务器随机产生一个字符串。所有,要模拟登陆的时候,必须要拿到xrsf。

用chrome (或者火狐 httpfox 抓包分析)的结果:

所以,必须要拿到xsrf的数值,注意这是一个动态变化的参数,每次都不一样。

拿到xsrf,下面就可以模拟登陆了。
使用requests库的session对象,建立一个会话的好处是,可以把同一个用户的不同请求联系起来,直到会话结束都会自动处理cookies。

注意:cookies 是当前目录的一个文件,这个文件保存了知乎的cookie,如果是第一个登陆,那么当然是没有这个文件的,不能通过cookie文件来登陆。必须要输入密码。

这是登陆的函数,通过login函数来登陆,post 自己的账号,密码和xrsf 到知乎登陆认证的页面上去,然后得到cookie,将cookie保存到当前目录下的文件里面。下次登陆的时候,直接读取这个cookie文件。

这是cookie文件的内容

以下是源码:

运行结果:

https://github.com/zhaozhengcoder/Spider/tree/master/spider_zhihu

反爬虫最基本的策略:

爬虫策略:
这两个都是在http协议的报文段的检查,同样爬虫端可以很方便的设置这些字段的值,来欺骗服务器。

反爬虫进阶策略:
1.像知乎一样,在登录的表单里面放入一个隐藏字段,里面会有一个随机数,每次都不一样,这样除非你的爬虫脚本能够解析这个随机数,否则下次爬的时候就不行了。
2.记录访问的ip,统计访问次数,如果次数太高,可以认为这个ip有问题。

爬虫进阶策略:
1.像这篇文章提到的,爬虫也可以先解析一下隐藏字段的值,然后再进行模拟登录。
2.爬虫可以使用ip代理池的方式,来避免被发现。同时,也可以爬一会休息一会的方式来降低频率。另外,服务器根据ip访问次数来进行反爬,再ipv6没有全面普及的时代,这个策略会很容易造成误伤。(这个是我个人的理解)。

通过Cookie限制进行反爬虫:
和Headers校验的反爬虫机制类似,当用户向目标网站发送请求时,会再请求数据中携带Cookie,网站通过校验请求信息是否存在Cookie,以及校验Cookie的值来判定发起访问请求的到底是真实的用户还是爬虫,第一次打开网页会生成一个随机cookie,如果再次打开网页这个Cookie不存在,那么再次设置,第三次打开仍然不存在,这就非常有可能是爬虫在工作了。

反爬虫进进阶策略:
1.数据投毒,服务器在自己的页面上放置很多隐藏的url,这些url存在于html文件文件里面,但是通过css或者js使他们不会被显示在用户看到的页面上面。(确保用户点击不到)。那么,爬虫在爬取网页的时候,很用可能取访问这个url,服务器可以100%的认为这是爬虫干的,然后可以返回给他一些错误的数据,或者是拒绝响应。

爬虫进进阶策略:
1.各个网站虽然需要反爬虫,但是不能够把百度,谷歌这样的搜索引擎的爬虫给干了(干了的话,你的网站在百度都说搜不到!)。这样爬虫应该就可以冒充是百度的爬虫去爬。(但是ip也许可能被识破,因为你的ip并不是百度的ip)

反爬虫进进进阶策略:
给个验证码,让你输入以后才能登录,登录之后,才能访问。

爬虫进进进阶策略:
图像识别,机器学习,识别验证码。不过这个应该比较难,或者说成本比较高。

参考资料:
廖雪峰的python教程
静觅的python教程
requests库官方文档
segmentfault上面有一个人的关于知乎爬虫的博客,找不到链接了

Python爬虫实战,Scrapy实战,爬取知乎表情包

前言

今天我们就用scrapy爬取知乎表情包。让我们愉快地开始吧~

开发工具

Python版本:3.6.4
相关模块:

scrapy模块

请求模块;

fake_useragent模块;

以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

原理简介

原理其实蛮简单的,因为之前就知道知乎有个api一直可以用:

https://www.zhihu.com/node/QuestionAnswerListV2
post请求这个链接,携带的数据格式如下:

data = {
           \'method\': \'next\',
           \'params\': \'{"url_token":%s,"page_size":%s,"offset":%s}\'
}
1. url_token:
问题id,譬如问题“https://www.zhihu.com/question/302378021”的问题id为302378021
2. page_size:
每页回答的数量(知乎最大只能是10)
3. offset:
当前显示的回答的偏移量

就可以获得该问题下的所有答案啦,然后用正则表达式提取每个回答下的所有图片链接就OK了。

具体实现的时候用的scrapy,先新建一个scrapy项目:

scrapy startproject zhihuEmoji

然后在spiders文件夹下新建一个zhihuEmoji.py文件,实现我们的爬虫主程序:

\'\'\'知乎表情包爬取\'\'\'
class zhihuEmoji(scrapy.Spider):
    name = \'zhihuEmoji\'
    allowed_domains = [\'www.zhihu.com\']
    question_id = \'302378021\'
    answer_url = \'https://www.zhihu.com/node/QuestionAnswerListV2\'
    headers = {
                \'user-agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36\',
                \'Accept-Encoding\': \'gzip, deflate\'
            }
    ua = UserAgent()
    \'\'\'请求函数\'\'\'
    def start_requests(self):
        offset = -10
        size = 10
        while True:
            offset += size
            data = {
                        \'method\': \'next\',
                        \'params\': \'{"url_token":%s,"page_size":%s,"offset":%s}\' % (self.question_id, size, offset)
                    }
            self.headers[\'user-agent\'] = self.ua.random
            yield scrapy.FormRequest(url=self.answer_url, formdata=data, callback=self.parse, headers=self.headers)
    \'\'\'解析函数\'\'\'
    def parse(self, response):
        # 用来保存图片
        if not os.path.exists(self.question_id):
            os.mkdir(self.question_id)
        # 解析响应获得问题回答中的数据, 然后获取每个回答中的图片链接并下载
        item = ZhihuemojiItem()
        answers = eval(response.text)[\'msg\']
        imgregular = re.compile(\'data-original="(.*?)"\', re.S)
        answerregular = re.compile(\'data-entry-url="\\\\\\\\/question\\\\\\\\/{question_id}\\\\\\\\/answer\\\\\\\\/(.*?)"\'.format(question_id=self.question_id), re.S)
        for answer in answers:
            item[\'answer_id\'] = re.findall(answerregular, answer)[0]
            image_url = []
            for each in re.findall(imgregular, answer):
                each = each.replace(\'\\\\\', \'\')
                if each.endswith(\'r.jpg\'):
                    image_url.append(each)
            image_url = list(set(image_url))
            for each in image_url:
                item[\'image_url\'] = each
                self.headers[\'user-agent\'] = self.ua.random
                self.download(requests.get(each, headers=self.headers, stream=True))
                yield item
    \'\'\'下载图片\'\'\'
    def download(self, response):
        if response.status_code == 200:
            image = response.content
            filepath = os.path.join(self.question_id, str(len(os.listdir(self.question_id)))+\'.jpg\')
            with open(filepath, \'wb\') as f:
                f.write(image)

其中ZhihuemojiItem()用于存储我们爬取的所有图片链接和对应的回答id,具体定义如下:

class ZhihuemojiItem(scrapy.Item):
    image_url = scrapy.Field()
    answer_id = scrapy.Field()

文章到这里就结束了,感谢你的观看,关注我每天分享Python爬虫实战系列,下篇文章分享大众点评爬虫。

为了感谢读者们,我想把我最近收藏的一些编程干货分享给大家,回馈每一个读者,希望能帮到你们。

干货主要有:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

All done~完整源代码+干货详见个人简介或者私信获取相关文件。。

以上是关于Python爬取知乎与我所理解的爬虫与反爬虫的主要内容,如果未能解决你的问题,请参考以下文章

Python-爬虫-爬取知乎的标题和当页显示的文字

python scrapy简单爬虫记录(实现简单爬取知乎)

Python爬虫实战,Scrapy实战,爬取知乎表情包

基于webmagic的爬虫小应用--爬取知乎用户信息

基于webmagic的爬虫小应用--爬取知乎用户信息

Python爬虫:爬取知乎上的视频,并把下载链接保存到md文件中