前言
- 最近看知乎老是给我推荐‘有个xxx的女朋友是什么体验?’这种类似的钓鱼问题,索性就打开电脑开始撸代码爬图片。
- 目标:把这个问题下所有回答下的图片下载到我的电脑。
1. 先来分析一下网页
1.1 打开问题网页
`https://www.zhihu.com/question/285906324/answer/603575032`
- 这里提一下其实不用登陆知乎也能访问到问题的回答页面,也就说可以不用cookie.
2. 用谷歌浏览器打开后进入控制台抓一下包。(这个都会吧,不会的话百度一下教程很多。)
-
2.1 寻找我们要的数据。
- 寻找一番后,可以发现在下面这个请求中服务器返回了一个json格式的数据(很激动有木有!!!)。同时我们将这个请求的url作为scrapy的初始url.
是的!!!在这个json数据中包含了我们想要的一切数据。包括每一个回答的 1. html代码,以及2.回答人的用户名,3.此回答的点赞数,评论数,以及4.此回答是否是最后一个回答。
- 寻找一番后,可以发现在下面这个请求中服务器返回了一个json格式的数据(很激动有木有!!!)。同时我们将这个请求的url作为scrapy的初始url.
-
2.2 数据的位置找到了,下一步确定代码怎么写。
- 图片url:这个在上一步的回答的html代码中,可以使用正则提取
- 图片分组:根据用户名分组。
- 筛选回答:毕竟不是每个回答下的都是。。。简单粗暴点,只下载点赞数大于500的。
- 翻页操作:根据返回的数据判断是否是最后一个回答。
写代码
我用的是scrapy框架,其实用request也是可以的只是我最近在练习scray。
- 新建项目zhihu
我默认你已经装好了scrapy,终端下输入:
scrapy startproject zhihu
- 创建爬虫
cd zhihu
scrapy genspider zh zhihu.com
- 下面是代码部分
- zh.py
# -*- coding: utf-8 -*-
from copy import deepcopy
import scrapy
import json
import re
class ZhSpider(scrapy.Spider):
name = 'zh'
allowed_domains = ['zhihu.com']
start_urls = ['https://www.zhihu.com/api/v4/questions/28046010/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%2Cis_labeled%2Cis_recognized%2Cpaid_info%2Cpaid_info_content%3Bdata%5B*%5D.mark_infos%5B*%5D.url%3Bdata%5B*%5D.author.follower_count%2Cbadge%5B*%5D.topics&offset=&limit=3&sort_by=default&platform=desktop']
def parse(self, response):
print("新的一页!")
dic = json.loads(response.text)
# 此相应中的三个回答、
answers_list = [answer for answer in dic.get('data') if answer.get('voteup_count') > 500]
for answer in answers_list:
item={}
item['voteup_count'] = answer.get('voteup_count')
author = answer.get('author').get('name')
item['author'] = author
answer_html_content = answer.get('content')
# 正则选出回答中的img url
incomplete_urls = re.findall(r'https:\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?',answer_html_content)
# 使用集合去除重复
img_urls = set([later_url for _, later_url in incomplete_urls])
for img_url in img_urls:
if img_url[-5] == 'r':
item["url"] = 'https://pic3.zhimg.com' + img_url
yield deepcopy(item)
if not dic.get('paging').get('is_end'):
next_url = dic.get('paging').get('next')
yield scrapy.Request(
next_url,
callback=self.parse
)
- 在settings.py的大约70行左右修改如下:
# 这段代码的作用是使用scray自带的下载图片的项目管道。除了这个方法也是可以使用requests模块实现的
ITEM_PIPELINES = {
'zhihu.pipelines.ZhihuPipeline': 300,
'scrapy.contrib.pipeline.images.ImagesPipeline': None,
# 如果需要采用自定义的ImagesPipiline,需要将自带的ImagesPipelin设置为None
'zhihu.pipelines.ImagesPipiline': 1
}
# 配置图片的保存目录
IMAGES_STORE = 'images'
# 在ImagesPipeline进行下载图片时,配置图片对应的Item字段
IMAGES_URLS_FIELD = 'img_url
- 在piplines.py中添加itempipelines
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.pipelines.images import ImagesPipeline
from scrapy.http import Request
class ZhihuPipeline(object):
def process_item(self, item, spider):
return item
class ImagesPipiline(ImagesPipeline):
def get_media_requests(self, item, info):
# 从item中获取要下载的图片的url,根据url构造Request()对象,并返回该对象
image_url = item['url']
yield Request(image_url, meta={'item': item})
def file_path(self, request, response=None, info=None):
# 用来自定义图片的下载路径
item = request.meta['item']
path = item.get('author')+ '/' + item.get("url")[28:]
#path = item.get("url")[28:]
return path
def item_completed(self, results, item, info):
# 图片下载完成后,返回结果result
print(results)
print("点赞数:{}".format(item.get('voteup_count')))
return item