python爬虫项目(新手教程)之知乎(requests方式)

-前言

之前一直用scrapy与urllib姿势爬取数据,最近使用requests感觉还不错,这次希望通过对知乎数据的爬取为 各位爬虫爱好者和初学者更好的了解爬虫制作的准备过程以及requests请求方式的操作和相关问题。当然这是一个简单的爬虫项目,我会用重点介绍爬虫从开始制作的准备过程,目的是为了让和我一样自学的爬虫爱好者和初学者更多的了解爬虫工作。

一、观察目标网页模板和策略

很多人都忽略这一步,其实这一步最为重要,因为它决定了你将采取什么策略来获取数据,也可以评估出你能够做到什么程度
(1)打开浏览器的开发工具F12

这里我用的是Google浏览器,打开浏览器按F12,你将看到你加载网页情况,以及网络请求的方式和交互的参数情况。如果你没有看到,你应该百度自己的浏览器开发者工具,如何打开。我们在打开知乎门户网页后,F12看到开发者工具的Network一栏没有出现任何东西。如图1.1所示:


开发者工具 图 1.1

然后我们在知乎搜索框内输入需要搜索的内容,你将会看到网页后台与前台数据交互的变化,加载的数据以及数据请求的方式和参数。如图1.2:


服务端与浏览器交互的信息 图1.2

这里你可以看到有很多js文件和png格式文件,这些文件都是通过你的搜索这个动作,对方服务器返回的文件,根据这些你可以更加了解网页服务端与浏览器的交互过程。这里如果你很有经验的话,可以根据它的size和name字段快速找出你想要的交互文件。
因为我们之前的搜索操作,所以很容易可以看出来第一个带有search字段的是搜索操作时和网站服务器交互的文件。点击我们可以看到 如图1.3:
与服务器通信请求参数 图1.3

这里有返回给我们与服务器通信后的过程以及相关数据,右上方可以看到Headers、Previes、Response、cookie等选项 。

  • headers可以看到请求的参数,我们很多时候写爬虫访问服务器被拒绝就是因为这里有很多参数验证没有通过,所以学会运用这里的参数是很有必要的。Requests Headers 是你请求时所用的请求头,重要的是cookie与User-Agent,cookie可以让你免登陆,虽然有时效性,但是有时候会帮助你节省时间,同时它有时候也是网站监测你是否是爬虫的手段,userAgent基本都会被服务端检测,所以每次请求都需要带上。Query String Parameters是你请求时所带的参数,因为这里是get方式请求,所以这里的参数在你的请求链接是可以看到的。post请求时,这里的参数会很重要,每次请求都必需带上这些参数,比如账号登录,你就可以在这里看到账号和密码。
  • Previes 这个文件内容就是网站将会呈现给你的东西,也就是预览
  • Response 可以看到返回的数据文本,有时候这里可以直接看到json数据,解决动态页面时,如果你能够直接找到想要的数据,你可以很轻松的避开js文件,直接访问这个文件获取数据。
    在知乎首页搜索后,你会发现没有换页,通过不停的下拉,会有新的数据产生。这里我们通过下拉时可以看到它产生了新的文件 如图 1.4:


    下拉后变化 图1.4

    多了一个search的请求文件,我们点开和第一个对比发现,offset字段从0变成了10。我们复制一下这里的url在新开的标签页粘贴后,发现如图1.5:


    复制链接的页面 图1.5

    看到返回的一个json类型的数据,这里中文都是unicode编码格式,所以我们需要自己写点代码,复制这些字符串,decode解码出中文。解码后你会发现,这些都是下拉时网页显示的数据。我们就可以通过正则表达式从这里将自己需要的数据提取出来,这里只是网页的第一层,为了进入第二层(点击一个链接,跳转的下一个页面),我们将提取这里所有的链接。
    回顾我之前文章requests介绍用法,很容易写出:
#假设每个搜索项有500页,如果没有想要的内容,可以break
for i in range(500):
      # key是要搜索的关键词
      url = 'https://www.zhihu.com/r/search?q='+key+'&correction=1&type=content&offset='+str(i*10)
      try:  #try用在这里,后面会解释原因
            response = requests.get(url,headers=headers)
      except:
            continue
       response.encoding='unicode-escape'
       page = lxml.html.fromstring(response.text)
       rule = re.compile('<a target="_blank" href="(.*?)"')
       hrefs = re.findall(rule,response.text)

好了第一层我们差不多做好了,进入网站第二层,随意点击一个我们搜索产生的内容标题,跳转至一个新的页面,我们用同样的方法,观察第二层我们与服务端交互的信息 如图 1.6:


第二层服务端交互信息 图1.6

这里有很多网络加载好的文件,我们需要找到具有关键信息的文件,如果各位有尝试在程序里直接请求你打开的url链接,会发现你得到的东西不是你在网上看到的,这是因为很多文件是通过浏览器渲染了js而得到的数据,而我们写的代码并没有这一步,所以我们很多时候用程序访问动态页面时,看不到数据。
当然你也可以添加这里面的js文件在代码中触发,但是这会变得很复杂,因为js文件作用很多,你要找到你想要的js文件并不容易。我们需要找到更快速有效的方法,这也是为什么“观察”是爬虫最重要的一环。
这里我们开始一个一个文件的去看,先看Response,你可以看到他返回的数据和内容。还有就是看它的文件名,这里的answers很容易可以猜到是评论和回答,我们点击进去Response看到数据,发现确实如我们所想
如图1.7:


回答请求参数页面 图1.7

有上次经验,可以准确知道offset是用来翻页的,limit是回答条数,我们同样复制这条链接,和第一层同样打开一个新的标签页,就能看到返回的json数据。我们要做的只需要通过解析工作,提取相关数据就行了。

二、爬虫的制作

通过观察所得到的结论,可以找到服务器的请求入口,从第一层找到翻页的链接,然后第二层获取数据。知乎第二层其实有几种版式,一种就是我们上文那种问答的形式,还有文章的形式,/question/ 和zhuanlan ,还有视频,这几种都要分开讨论,分别解析。我这里只介绍问答和文章的解析方式,方法都大同小异。

(1) 搜索关键词进入相关页面
import requests
import re
import lxml.html
    keys = ['.....']  #key 自己定义一个list
    for key in keys:
      #假设有500页
      for i in range(500):
          url = 'https://www.zhihu.com/r/search?q='+key+'&correction=1&type=content&offset='+str(i*10)
          try:
              response = requests.get(url,headers=headers)
          except:
              continue
         response.encoding='unicode-escape'
         page = lxml.html.fromstring(response.text)
         rule = re.compile('<a target="_blank" href="(.*?)"')
         hrefs = re.findall(rule,response.text)
         rule2 = re.compile('<em>(.*?)<')
         keyword = re.findall(rule2,response.text)
         response.close()
         hrefs = [i.replace('\\','') for i in hrefs]
         if key in keyword:
             for href in hrefs:
                if 'question' in href:
                     num = href.replace('/question/','')
                     GetQuestionMsg(key,num)
                elif 'zhuanlan' in href:
                    GetPageMsg(key,href)
         else:
            break
(2) 文章样式提取数据
def GetPageMsg(key,url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36'
    }
    try:
        response = requests.get(url,headers=headers)
    except:
        return
    #print(response.status_code)
    print(key)  
   #这里我用xpath方式来解析网页文本
    page = lxml.html.fromstring(response.text)
    title = page.xpath('//title/text()')
    title = title[0]
    content = page.xpath('//div[@class="RichText Post-RichText"]//p/text()')
(3)问答模板提取数据
def GetQuestionMsg(key,num):
 #这里假设它有500页
    for i in range(500):
        url = 'https://www.zhihu.com/api/v4/questions/'+num+'/answers?include=data%5B*%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B*%5D.mark_infos%5B*%5D.url%3Bdata%5B*%5D.author.follower_count%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset='+str(i*20)+'&limit=20&sort_by=created'
        headers = {
          'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36'
         }
        #自行添加自己的cookie值,按第一步所说步骤,复制添加访问此处网页的Requests Headers中的cookie
        cookies={
            '_zap':'',
            ' q_c1':'',
            ' d_c0':'',
            ' z_c0':'',
            ' __DAYU_PP':'',
            ' q_c1':'',
            ' aliyungf_tc':'',
            ' _xsrf':'',
            ' __utmc':'',
            ' __utmv':'',
            ' __utmz':'',
            ' __utma':'',
            ' s-q':'',
            ' sid':'',    
            ' s-i':'',
            }
        try:
            response = requests.get(url,headers=headers,cookies=cookies)
        except:
            return
        response.encoding='unicode-escape'
        print(key)   
        rule = re.compile('"excerpt": "(.*?)"')
        content = re.findall(rule,response.text)
        rule2 = re.compile('"title": "(.*?)"')
        title = re.findall(rule2,response.text)
        content =','.join(content)
        response.close()
        try:
            print(title[1])
            title = title[1]
            print(content)
        except:
            return

问答时候,添加了cookies,因为直接访问得不到数据,所以我们需要模拟我们观察得到的请求头信息,添加了cookies,发现访问成功。

三、测试与问题

用requests爬知乎的过程中,经常会遇到一个异常

requests.exceptions.ConnectionError: HTTPSConnectionPool: Max retries exceeded with url:

百度出来的解释说requests连接请求次数超过了限制次数,需要关闭连接或设置更大的默认连接数,但我都尝试了,还是会有这种问题。我想应该是其它原因导致的这个错误,所以我在每次的response= response.get()时都要加try,抛出异常来保证程序持续运行。如果你们有更好的解决方案和对这个问题的理解,请您回复我或者私信我,不甚感激。

结语

知乎爬虫项目到这里就告一段落了,前期工作讲的比较细,因为我觉得作为爬虫工程师对前期工作应该要重视,我之前没有重视,所以填了很多坑,走了很多弯路,所以借这个项目来讲下爬虫工程师前期工作,当然我讲的只是一小块,实际工作有的会更加复杂,有时候找很久都找不到获取数据入口,有时候找到了获取途径又需要参数验证,甚至好不容易获取到了数据,才发现网站能提供的数据量远远不够,这都是前期工作需要做好的内容。这一章献给和我一样自学的爬虫爱好者与初学者。

如果您喜欢我的文章,请关注或点击喜欢,您的支持是我最大的动力 ^ ^~!
转载请注明作者及其出处

黑羊的皇冠 简书主页

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 目录: Python网络爬虫(一)- 入门基础Python网络爬虫(二)- urllib爬虫案例Python网络爬...
    一只写程序的猿阅读 12,712评论 17 68
  • 声明:本文讲解的实战内容,均仅用于学习交流,请勿用于任何商业用途! 一、前言 强烈建议:请在电脑的陪同下,阅读本文...
    Bruce_Szh阅读 12,586评论 6 28
  • http header 消息通常被分为4个部分:general header即头部, request header...
    徐薇薇阅读 31,722评论 0 5
  • 这个时候,如果有你,应该不会是这样的境地。 你总是出现在我最需要你的时候,只可惜……太可惜。 知己难寻。我最近开始...
    KEIK0阅读 73评论 0 0