前些天写的一篇"我与Scrapy的初次相识,理论+实战入门Scrapy "都上首页推荐了,到现在浏览量还没破百,难受。
写的不好大概,不过只要有一人看,都是鼓励,一直写,一直积淀,终成大佬,给自己加油。


言归正传,直入主题,用Scrapy爬取知乎Python专题精华,连答主的头像都给爬下来,不放过一切,片草不留。

实在话,答主的头像爬下来也不知道干嘛,主要是想练习以下两点:

  1. Scrapy爬取图片,并重命名图片(即重写imagePipeline)
  2. Scrapy多个Item多个Pipeline的相关处理

从百度进知乎的专题曲曲折折的,大家直接点我这链接去:https://www.zhihu.com/topic/19552832/top-answers

写代码? 不急,首要的是先创建一个Scrapy项目了,框架有了,后面才能添砖加瓦。在终端依次输入指令。

# 创建项目
scrapy startproject zhihu# 进入到项目目录下
cd zhihu# 创建Spider文件 python_zhihu为项目名 zhihu.com为限定的爬取网域
scrapy genspider python_zhihu zhihu.com

1.分析网页,找到数据在哪

1.1、是不是异步加载?

数据无非是在html文件或者是异步加载出来的,我发现知乎这个专题精华没有分页栏,往下拉加载数据URL地址也没有发生变化,断定这个网页是个异步加载,我们打开开发者工具去XHR文件中查找。

1.2、网页里数据的结构是什么样的?

刚刷新网页那会,出来的文件确实没有什么可用的数据,但是伴随着网页往下滚动加载数据,出来了有用的数据了,如下可以看出这个文件返回的正是这文章josn格式的相关数据。这是Preview模块,方便查看返回了数据的结构。

这里我们就可以编写Item的代码了。
分析json数据,编写Item。

我这里就不贴代码了,放个截图,这代码真得自己敲了才有印象,若是有哪里不清楚可以来讨论一下的,最后搞不定的情况(必定有细节错误)再发源码。

特意说明:爬取头像的Item中image_urls和images这两个是Scrapy自带的Image管道默认的名称,尽可能不要修改,另外一个image_name是为了重写ImagePipeline,修改图片的名称才加进去的,后面再说。

1.3、请求的网址呢?

知道了上面的json数据离爬取是进了一步,那我们需要知道如何请求到这些数据,去这个文件的Headers模块查看,以下是截图。

不知道大家有没有看到这api几字,这里调用api来获取数据再方便不过了,通过URL末尾的offset和limit两个参数来控制获取的页数和每页的数据量。

2.构建Spider爬虫,爬取数据

2.1、解析response,解析出数据

和普通的网络爬虫不一样,Scrapy的下载器已经下载好了网页,我们只需要解析它的response就行了。

这里有两个try-except,主要是解决掉下面两个问题。
问题1:返回的json数据中,不全是文章的数据,我没细分析,不清楚那些个无关的数据是哪的。

问题2:有些用户是匿名回答的,或者已经注销了账号了,没有详情页链接的,爬取时把它设置成”未知用户“。

因为每次返回的json数据不尽是文章内容,所以逻辑上,到这里至少能够爬取一条的文章的信息。

2.2、测试发现的问题

插一句,之前为了初步测试一下,我先把piplines和settings两个文件配置起来了(这里测试的我就不细说了,主要说一下出现的问题)。

文本信息爬取倒是没事,安然无恙,这使用自带的ImagePipline倒是出了如下两个问题,已解决。
问题1: ModuleNotFoundError: No module named ‘scrapy.contrib’


解决方案:

问题2: raise ValueError(‘Missing scheme in request url: %s’ % self._url)

解决方案:
原本是下图中的String类型,但是image_urls要求的是list类型,所以强转一下。

修改为

另外图片爬取下来后,有如下一个缺陷,Scrapy自带的图片管道下载的图片名称是它们URL的 SHA1 hash值,不是很好看,所以要重写它的ImagePipeline,修改图片的名称。

2.3、piplines和settings的设置

上一步插了一句测试,这步要重归正题,讲一下pipelines和settings的配置了,不然有些人要犯迷糊了。
piplines文件中设置了两个pipline分别对Items中的两个item进行处理。
另外因为Scrapy传item是一股脑就都传来了,这两个pipline分不清楚哪个是自己需要处理的item,直接运行会报错误,所以在函数接收item后要对item进行辨别,使用 isinstance() 方法对item进行判断类型相同与否。

值得一提的是,这些个Pipline当中的函数名都是默认的,我们只是对它进行重写,所以不能修改函数名称。

settings文件 一配置完,这个项目真就完全可以跑起来了。

ITEM_PIPELINES里每个pipeline后面的整数型数值是指它运行的优先级,或者说距离,数值越小,距离越近,越先执行。

2.4、翻页请求下一页怎么做?

前面配置了item、spider、piplines、settings四个文件,项目也就完成,但是之前也就只爬取了一页的数据,所以,我们还要在Spider中的parse函数中加上翻页请求下一页的代码。

这里给大家伙看一眼最后的结果,好叫大家伙安心,这个代码是可以运行的。

以下为自娱自乐环节

Q:当真不贴源码,你写的博文全是图,不方便借鉴呀

A:当真不发,图上注释也很清楚了,自己敲更有印象,看看代码截图再自己思考一下更有收获


Q:其实我知道你想发源码的,不然整这么大的加粗黑字在这里干嘛

A:好吧,被你发现了,是担心自己有些细节没表达好,导致大家伙最终的没爬到数据


Q:不对不对,你必定还有别的想法,爬虫主要是思路,每个网页的结构不同,学会一个代码只能说会了一个爬虫代码而已,要学会思路自己去分析才是王道

A:知己呀,还是你懂我,我其实就是想让那些个看见没源代码的童鞋早早的走,不要误了他们学习其他有源码的。


Q:哈哈哈哈,快行动起来,早知你有诈,我前面没看就翻到文末来了

A:哎呀,可恶,道高一尺魔高一丈,不过我这里还是要给好好学习的童鞋们贴上源码的,让他们好好研究,不要错了什么细节,尽情享用


Spider

# -*- coding: utf-8 -*-
import scrapy
import json
from ..items import ZhihuItem, ZhihuUserImageItemclass PythonZhihuSpider(scrapy.Spider):name = 'python_zhihu'start_urls = ['https://www.zhihu.com/api/v4/topics/19552832/feeds/essence?include=data%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Danswer)%5D.target.content%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Danswer)%5D.target.is_normal%2Ccomment_count%2Cvoteup_count%2Ccontent%2Crelevant_info%2Cexcerpt.author.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Darticle)%5D.target.content%2Cvoteup_count%2Ccomment_count%2Cvoting%2Cauthor.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Dpeople)%5D.target.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Danswer)%5D.target.annotation_detail%2Ccontent%2Chermes_label%2Cis_labeled%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%3Bdata%5B%3F(target.type%3Danswer)%5D.target.author.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Darticle)%5D.target.annotation_detail%2Ccontent%2Chermes_label%2Cis_labeled%2Cauthor.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dquestion)%5D.target.annotation_detail%2Ccomment_count%3B&offset=0&limit=10']def parse(self, response):item = ZhihuItem()imageItem = ZhihuUserImageItem()datas = json.loads(response.body)['data']for data in datas:try:item['id'] = data['target']['id']item['title'] = data['target']['title']item['url'] = data['target']['url']item['content'] = data['target']['content']item['voteup_count'] = data['target']['voteup_count']item['comment_count'] = data['target']['comment_count']item['author_name'] = data['target']['author']['name']try:item['author_url'] = 'https://www.zhihu.com/' + data['target']['author']['user_type'] + data['target']['author']['url_token']except Exception as e:item['author_url'] = '未知用户'passyield itemimageItem['image_urls'] = [data['target']['author']['avatar_url']]imageItem['image_name'] = data['target']['author']['name']yield imageItemexcept Exception as e:pass# 进行下几页的爬取url = 'https://www.zhihu.com/api/v4/topics/19552832/feeds/essence?include=data%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Danswer)%5D.target.content%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Danswer)%5D.target.is_normal%2Ccomment_count%2Cvoteup_count%2Ccontent%2Crelevant_info%2Cexcerpt.author.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Darticle)%5D.target.content%2Cvoteup_count%2Ccomment_count%2Cvoting%2Cauthor.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dtopic_sticky_module)%5D.target.data%5B%3F(target.type%3Dpeople)%5D.target.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Danswer)%5D.target.annotation_detail%2Ccontent%2Chermes_label%2Cis_labeled%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%3Bdata%5B%3F(target.type%3Danswer)%5D.target.author.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Darticle)%5D.target.annotation_detail%2Ccontent%2Chermes_label%2Cis_labeled%2Cauthor.badge%5B%3F(type%3Dbest_answerer)%5D.topics%3Bdata%5B%3F(target.type%3Dquestion)%5D.target.annotation_detail%2Ccomment_count%3B&limit=10&offset={}'page = 10for i in range(5, 15 + 10*int(page), 10):yield scrapy.Request(url=url.format(i), callback=self.parse)

items

# -*- coding: utf-8 -*-# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.htmlimport scrapyclass ZhihuItem(scrapy.Item):id = scrapy.Field()title = scrapy.Field()url = scrapy.Field()content = scrapy.Field()voteup_count = scrapy.Field()comment_count = scrapy.Field()author_name = scrapy.Field()author_url = scrapy.Field()pass# 爬取用户头像的Item
class ZhihuUserImageItem(scrapy.Item):image_urls = scrapy.Field()images = scrapy.Field()image_name = scrapy.Field()pass

Piplines

# -*- coding: utf-8 -*-# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
import csv
import refrom .items import ZhihuItem
from .items import ZhihuUserImageItemclass ZhihuPipeline(object):def __init__(self):file = './data.csv'self.file = open(file, 'a+', encoding="utf-8", newline='')self.writer = csv.writer(self.file, dialect="excel")def process_item(self, item, spider):if isinstance(item, ZhihuItem):item['content'] = re.sub('<.*?>', '', re.sub('</p>', '\n', item['content']))self.writer.writerow([item['id'], item['title'], item['url'], item['content'],item['voteup_count'], item['comment_count'], item['author_name'], item['author_url']])print('已进入文本管道')return itemdef close_spider(self, spider):self.file.close()class UserImagePipeline(ImagesPipeline):def get_media_requests(self, item, info):if isinstance(item, ZhihuUserImageItem):for image_url in item['image_urls']:yield Request(image_url, meta={'name': item['image_name']})def item_completed(self, results, item, info):if isinstance(item, ZhihuUserImageItem):image_path = [x['path'] for ok, x in results if ok]if not image_path:raise DropItem('Item contains no images')print('已进入图片管道')return itemdef file_path(self, request, response=None, info=None):image_name = request.meta['name']filename = image_name + '.jpg'return filename

Settings

# -*- coding: utf-8 -*-# Scrapy settings for zhihu project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://doc.scrapy.org/en/latest/topics/settings.html
#     https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://doc.scrapy.org/en/latest/topics/spider-middleware.htmlBOT_NAME = 'zhihu'SPIDER_MODULES = ['zhihu.spiders']
NEWSPIDER_MODULE = 'zhihu.spiders'LOG_LEVEL = 'ERROR'# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'zhihu (+http://www.yourdomain.com)'
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'# Obey robots.txt rules
ROBOTSTXT_OBEY = False# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {'zhihu.pipelines.ZhihuPipeline': 300,'zhihu.pipelines.UserImagePipeline': 10,
}IMAGES_STORE = 'images'
IMAGES_EXPIRES = 90

Scrapy爬取知乎Python专题精华,连答主头像都给爬下来,不放过一切相关推荐

  1. python爬取知乎话题的精华问题下的用户信息

    今天试着用自己的爬虫代码爬取了知乎[同性恋]话题下的所有精华问题的用户位置信息 代码: __author__ = 'yang' # -*- coding: utf-8 -*-import config ...

  2. python xpath爬取新闻标题_爬取知乎热榜标题和连接 (python,requests,xpath)

    用python爬取知乎的热榜,获取标题和链接. 环境和方法:ubantu16.04.python3.requests.xpath 1.用浏览器打开知乎,并登录 2.获取cookie和User-Agen ...

  3. 如何爬取知乎中问题的回答以及评论的数据?

    如何爬取知乎中问题的回答以及评论的数据? 我们以爬取"为什么中医没有得到外界认可?"为例来讨论一下如何爬取知乎中问题的回答以及评论的数据. 爬取网页数据通常情况下会经历以下三个步骤 ...

  4. python爬取知乎live_【实战视频教程】使用scrapy爬知乎live信息

    [公众号:大邓python]用scrapy爬取知乎live_腾讯视频https://v.qq.com/x/cover/u0551wi70m1/u0551wi70m1.html 一.知乎Live抓包分析 ...

  5. python scrapy框架爬取知乎提问信息

    前文介绍了python的scrapy爬虫框架和登录知乎的方法. 这里介绍如何爬取知乎的问题信息,并保存到mysql数据库中. 首先,看一下我要爬取哪些内容: 如下图所示,我要爬取一个问题的6个信息: ...

  6. 使用python scrapy爬取知乎提问信息

    前文介绍了python的scrapy爬虫框架和登录知乎的方法. 这里介绍如何爬取知乎的问题信息,并保存到mysql数据库中. 首先,看一下我要爬取哪些内容: 如下图所示,我要爬取一个问题的6个信息: ...

  7. python爬虫实战笔记---以轮子哥为起点Scrapy爬取知乎用户信息

    开发环境:python3.5+Scrapy+pycharm+mongodb 思路: 1.选定起始人:选定一个关注数量或粉丝数量多的大佬 2.获取粉丝和关注列表 3.获取列表用户信息 4.获取每位用户粉 ...

  8. scrapy实战项目(简单的爬取知乎项目)

    本项目实现了对知乎用户信息的爬取,并没有用数据库等,只是简单地用一些提取了一些字段然后存储在了一个csv文件中,但是同样可以实现无线爬取,理论上可以实现万级数据的爬取(当然取决于网速了) 其实想爬取知 ...

  9. python爬虫知乎点赞_Python爬虫爬取知乎小结

    最近学习了一点网络爬虫,并实现了使用Python来爬取知乎的一些功能,这里做一个小的总结.网络爬虫是指通过一定的规则自动的从网上抓取一些信息的程序或脚本.我们知道机器学习和数据挖掘等都是从大量的数据出 ...

最新文章

  1. POJ 2104 K-th Number
  2. python编程 入门到实践-Python编程入门到实践(二)
  3. 【shell】shell编程(四)-循环语句
  4. 3分钟内看完这,bootstraptable表格控件,受益匪浅!
  5. 一款不错的开源 Laravel 后台面板/CMS系统 —— LaraAdmin
  6. 如何破解受保护的excel密码
  7. github结合TortoiseGit使用sshkey,无需输入账号和密码
  8. Boost::asio概览
  9. 永川机器人五小区_永川清掏化粪池报价---蚂众蚁
  10. Tcl Tutorial 笔记1 · 输出
  11. 【Notification】屏蔽特定应用的通知提示
  12. 分享如何恢复回收站删除文件的办法
  13. 经典算法电话号码的字母组合
  14. IOS塔防游戏《坦克对大炮》的开发设计记录
  15. vs下载安装编写c++示例(避坑一个项目下多个main)
  16. 大学期间-Fans同学的11个艰难的决定
  17. 优必选将推出家庭守卫机器人——“第一军团风暴兵”机器人
  18. ngnix有版本要求吗_DNF:5.21版本更新,安图恩版本回归,熟悉的机制来临
  19. 案例:同程凤凰缓存系统基于Redis的设计与实践。
  20. 深田之星备件仓库管理系统2011

热门文章

  1. 荐书:理解知识图谱必看的那些书、公众号和其他资料
  2. 移动GPU渲染原理的流派——IMR、TBR及TBDR
  3. 办公计算机应用常用软件,办公自动化及常用工具软件
  4. 实验名称: 类的构造函数、析构函数和友员成员应用
  5. 在 Excel 中查询每个区间并排序
  6. C# 数据库介绍及基本操作
  7. ROS控制桌面机械手Dobot魔术师
  8. 论文复现:Learning Efficient Convolutional Networks through Network Slimming
  9. 男孩年级轻轻就猝死,看到他最后时刻做的事,我被警醒了(漫画)
  10. 小程序瀑布流_小程序界面设计 | 太古可口可乐会员平台