(直接需要代码的看最后面,前面只是分析)
当你查看知乎某个问题的答案时,通过普通的方法爬取页面,你发现只能爬取一页的内容,当你点击下一页时,浏览器地址并没有发生变化,这种技术叫做AJAX,每次载入的只是部分数据,当知道这个后,就可以构造特殊的头部来请求获得数据。
知乎问题下的解析:
可以看到请求页面的方式GET,请求的地址为Request URL,请求头的构成为Request Header的内容,有点长是不是。
Request Header:
还有一个就是Query String Parameters
这是什么呢,这就是我们Request URL的请求的数据部分了,他是怎么区分页面的呢,我们看第二页的请求数据
两者不同的是 offset这个值,而知乎一个页面的回答数量刚好是20,也就是差值。
到这里我们就可以知道怎么样获取我们请求的数据了:
用GET方法向指定URL发送我们的请求数据
下面是代码实现:
import urllib.request import json import urllib.parse import re import random n=0 for i in range(0,10): #爬取十页的回答的图片 url='https://www.zhihu.com/api/v4/questions/27761934/answers?' #请求URL地址 data={} head={} #head为请求头部封装 head['User-Agent']='Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36' head['accept']='application/json, text/plain, */*' # head['Accept-Encoding']='utf-8, deflate, sdch, br' head['Accept-Language']='zh-CN,zh;q=0.8' head['Referer']='https://www.zhihu.com/question/27761934' head['authorization']='oauth c3cef7c66a1843f8b3a9e6a1e3160e20' head['Connection']='keep-alive' head['host']='www.zhihu.com' head['Cookie']='q_c1=cb235bc32c3c4ff6a13d539ab32932ed|1491640993000|1491640993000;' \ ' r_cap_id="OTk4MDc1ZTYzZTYxNDhkMGFkZmMzZmMyY2MzYTQ0MWM=|1492689948|ea65e09abdd21db7eecd997d1e7689d7213005c8"; ' \ 'cap_id="ZWY2NDA1MTc3ZjAzNDc2MWFmNTQ4YjFkY2NhNzdmZjM=|1492689948|16df8cfc942dcae5adc9ffa5395afbdcc87bf39a";' \ ' l_cap_id="ZGNkOGVmZTgzNDk0NGJjOTljMzU0Mjc0MGY2YmU1ODE=|1492689948|2768d12cd0236bb96722f7216b307ba799d4bf19"; ' \ 'aliyungf_tc=AQAAABxPakPO4goAgVG3PSefHqc6PP2k; acw_tc=AQAAAEUxcRqsHQwAgVG3PZaK3p0hk5Lq' #data为数据部分 data['sort_by']='default' data['include']='data[*].is_normal,is_sticky,collapsed_by,suggest_edit,comment_count,' \ 'can_comment,content,editable_content,voteup_count,reshipment_settings,' \ 'comment_permission,mark_infos,created_time,updated_time,' \ 'relationship.is_authorized,is_author,voting,is_thanked,is_nothelp,' \ 'upvoted_followees;data[*].author.badge[?(type=best_answerer)].topics' data['limit']=20 data['offset']=3+20*i data=urllib.parse.urlencode(data).encode('utf-8') req=urllib.request.Request(url,data,head,method='GET') #需指定方法,默认是为POST的 req = urllib.request.urlopen(req) re_data = req.read().decode('gbk') print(re_data) pe='https:.{0,80}jpg' #构造的正则,有点丑陋。。。 url1=re.compile(pe) num=0 q=random.randint(1,20) for x in url1.findall(re_data): if 'https' in x: print(x) try: if(num%4==0): urllib.request.urlretrieve(x, 'F:\\ccc3\\test\\mmmmmm'+str(q)+'%s.jpg' % num) print('下载第'+str(n) + '张图片') n+=1 except:print('error') num +=1
其中head的cookie,host,connection等都是可以省略的。
已知缺陷:json里同一个链接出现四次,我用num处理的有点难看
有最大爬取数,不超过一千,可以用ip池解决
正则丑陋。
爬取别的问题需要修改的是URL里的数字及head['Referer']里的数字,数字为问题的代码,代码为:
里面的数字,如果代码不能运行请修改cookie和authorization为自己的.
如还不能运行,评论或者私信我