侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

一步步教你用python的scrapy编写一个爬虫

Python  /  管理员 发布于 7年前   202

介绍

本文将介绍我是如何在python爬虫里面一步一步踩坑,然后慢慢走出来的,期间碰到的所有问题我都会详细说明,让大家以后碰到这些问题时能够快速确定问题的来源,后面的代码只是贴出了核心代码,更详细的代码暂时没有贴出来。

流程一览

首先我是想爬某个网站上面的所有文章内容,但是由于之前没有做过爬虫(也不知道到底那个语言最方便),所以这里想到了是用python来做一个爬虫(毕竟人家的名字都带有爬虫的含义😄),我这边是打算先将所有从网站上爬下来的数据放到ElasticSearch里面, 选择ElasticSearch的原因是速度快,里面分词插件,倒排索引,需要数据的时候查询效率会非常好(毕竟爬的东西比较多😄),然后我会将所有的数据在ElasticSearch的老婆kibana里面将数据进行可视化出来,并且分析这些文章内容,可以先看一下预期可视化的效果(上图了),这个效果图是kibana6.4系统给予的帮助效果图(就是说你可以弄成这样,我也想弄成这样😁)。后面我会发一个dockerfile上来(现在还没弄😳)。

环境需求

  • Jdk (Elasticsearch需要)
  • ElasticSearch (用来存储数据)
  • Kinaba (用来操作ElasticSearch和数据可视化)
  • Python (编写爬虫)
  • Redis (数据排重)

这些东西可以去找相应的教程安装,我这里只有ElasticSearch的安装😢点我获取安装教程

第一步,使用python的pip来安装需要的插件(第一个坑在这儿)

1.tomd:将html转换成markdown

pip3 install tomd

2.redis:需要python的redis插件

pip3 install redis

3.scrapy:框架安装(坑)

  1、首先我是像上面一样执行了

pip3 install scrapy

   2、然后发现缺少gcc组件 error: command 'gcc' failed with exit status 1

   3、然后我就找啊找,找啊找,最后终于找到了正确的解决方法(期间试了很多错误答案😭)。最终的解决办法就是使用yum来安装python34-devel,  这个python34-devel根据你自己的python版本来,可能是python-devel,是多少版本就将中间的34改成你的版本, 我的是3.4.6

yum install python34-devel

   4、安装完成过后使用命令 scrapy 来试试吧。


第二步,使用scrapy来创建你的项目

输入命令scrapy startproject scrapyDemo, 来创建一个爬虫项目

liaochengdeMacBook-Pro:scrapy liaocheng$ scrapy startproject scrapyDemoNew Scrapy project 'scrapyDemo', using template directory '/usr/local/lib/python3.7/site-packages/scrapy/templates/project', created in:/Users/liaocheng/script/scrapy/scrapyDemoYou can start your first spider with:cd scrapyDemoscrapy genspider example example.comliaochengdeMacBook-Pro:scrapy liaocheng$ 

使用genspider来生成一个基础的spider,使用命令scrapy genspider demo juejin.im, 后面这个网址是你要爬的网站,我们先爬自己家的😂

liaochengdeMacBook-Pro:scrapy liaocheng$ scrapy genspider demo juejin.imCreated spider 'demo' using template 'basic'liaochengdeMacBook-Pro:scrapy liaocheng$ 

查看生成的目录结构


第三步,打开项目,开始编码

查看生成的的demo.py的内容

# -*- coding: utf-8 -*-import scrapyclass DemoSpider(scrapy.Spider): name = 'demo' ## 爬虫的名字 allowed_domains = ['juejin.im'] ## 需要过滤的域名,也就是只爬这个网址下面的内容 start_urls = ['https://juejin.im/post/5c790b4b51882545194f84f0'] ## 初始url链接 def parse(self, response): ## 如果新建的spider必须实现这个方法 pass

可以使用第二种方式,将start_urls给提出来

# -*- coding: utf-8 -*-import scrapyclass DemoSpider(scrapy.Spider): name = 'demo' ## 爬虫的名字 allowed_domains = ['juejin.im'] ## 需要过滤的域名,也就是只爬这个网址下面的内容 def start_requests(self): start_urls = ['http://juejin.im/'] ## 初始url链接 for url in start_urls:  # 调用parse  yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): ## 如果新建的spider必须实现这个方法 pass

编写articleItem.py文件(item文件就类似java里面的实体类)

import scrapyclass ArticleItem(scrapy.Item): ## 需要实现scrapy.Item文件 # 文章id id = scrapy.Field() # 文章标题 title = scrapy.Field() # 文章内容 content = scrapy.Field() # 作者 author = scrapy.Field() # 发布时间 createTime = scrapy.Field() # 阅读量 readNum = scrapy.Field() # 点赞数 praise = scrapy.Field() # 头像 photo = scrapy.Field() # 评论数 commentNum = scrapy.Field() # 文章链接 link = scrapy.Field()

编写parse方法的代码

 def parse(self, response): # 获取页面上所有的url nextPage = response.css("a::attr(href)").extract() # 遍历页面上所有的url链接,时间复杂度为O(n) for i in nextPage:  if nextPage is not None:  # 将链接拼起来  url = response.urljoin(i)  # 必须是掘金的链接才进入  if "juejin.im" in str(url):   # 存入redis,如果能存进去,就是一个没有爬过的链接   if self.insertRedis(url) == True:   # dont_filter作用是是否过滤相同url true是不过滤,false为过滤,我们这里只爬一个页面就行了,不用全站爬,全站爬对对掘金不是很友好,我么这里只是用来测试的    yield scrapy.Request(url=url, callback=self.parse,headers=self.headers,dont_filter=False) # 我们只分析文章,其他的内容都不管 if "/post/" in response.url and "#comment" not in response.url:  # 创建我们刚才的ArticleItem  article = ArticleItem()  # 文章id作为id  article['id'] = str(response.url).split("/")[-1]  # 标题  article['title'] = response.css("#juejin > div.view-container > main > div > div.main-area.article-area.shadow > article > h1::text").extract_first()  # 内容  parameter = response.css("#juejin > div.view-container > main > div > div.main-area.article-area.shadow > article > div.article-content").extract_first()  article['content'] = self.parseToMarkdown(parameter)  # 作者  article['author'] = response.css("#juejin > div.view-container > main > div > div.main-area.article-area.shadow > article > div:nth-child(6) > meta:nth-child(1)::attr(content)").extract_first()  # 创建时间  createTime = response.css("#juejin > div.view-container > main > div > div.main-area.article-area.shadow > article > div.author-info-block > div > div > time::text").extract_first()  createTime = str(createTime).replace("年", "-").replace("月", "-").replace("日","")  article['createTime'] = createTime  # 阅读量  article['readNum'] = int(str(response.css("#juejin > div.view-container > main > div > div.main-area.article-area.shadow > article > div.author-info-block > div > div > span::text").extract_first()).split(" ")[1])  # 点赞数  article['badge'] = response.css("#juejin > div.view-container > main > div > div.article-suspended-panel.article-suspended-panel > div.like-btn.panel-btn.like-adjust.with-badge::attr(badge)").extract_first()  # 评论数  article['commentNum'] = response.css("#juejin > div.view-container > main > div > div.article-suspended-panel.article-suspended-panel > div.comment-btn.panel-btn.comment-adjust.with-badge::attr(badge)").extract_first()  # 文章链接  article['link'] = response.url  # 这个方法和很重要(坑),之前就是由于执行yield article, pipeline就一直不能获取数据  yield article# 将内容转换成markdowndef parseToMarkdown(self, param): return tomd.Tomd(str(param)).markdown# url 存入redis,如果能存那么就没有该链接,如果不能存,那么就存在该链接def insertRedis(self, url): if self.redis != None: return self.redis.sadd("articleUrlList", url) == 1 else: self.redis = self.redisConnection.getClient() self.insertRedis(url)

编写pipeline类,这个pipeline是一个管道,可以将所有yield关键字返回的数据都交给这个管道处理,但是需要在settings里面配置一下pipeline才行

from elasticsearch import Elasticsearchclass ArticlePipelines(object): # 初始化 def __init__(self): # elasticsearch的index self.index = "article" # elasticsearch的type self.type = "type" # elasticsearch的ip加端口 self.es = Elasticsearch(hosts="localhost:9200") # 必须实现的方法,用来处理yield返回的数据 def process_item(self, item, spider):  # 这里是判断,如果是demo这个爬虫的数据才处理 if spider.name != "demo":  return item result = self.checkDocumentExists(item) if result == False:  self.createDocument(item) else:  self.updateDocument(item) # 添加文档 def createDocument(self, item): body = {  "title": item['title'],  "content": item['content'],  "author": item['author'],  "createTime": item['createTime'],  "readNum": item['readNum'],  "praise": item['praise'],  "link": item['link'],  "commentNum": item['commentNum'] } try:  self.es.create(index=self.index, doc_type=self.type, id=item["id"], body=body) except:  pass # 更新文档 def updateDocument(self, item): parm = {  "doc" : {  "readNum" : item['readNum'],  "praise" : item['praise']  } } try:  self.es.update(index=self.index, doc_type=self.type, id=item["id"], body=parm) except:  pass # 检查文档是否存在 def checkDocumentExists(self, item): try:  self.es.get(self.index, self.type, item["id"])  return True except:  return False

第四步,运行代码查看效果

使用scrapy list查看本地的所有爬虫

liaochengdeMacBook-Pro:scrapyDemo liaocheng$ scrapy listdemoliaochengdeMacBook-Pro:scrapyDemo liaocheng$ 

使用scrapy crawl demo来运行爬虫

 scrapy crawl demo

到kibana里面看爬到的数据,执行下面的命令可以看到数据

GET /article/_search{ "query": { "match_all": {} }}
{ "took": 7, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "article2", "_type": "type", "_id": "5c790b4b51882545194f84f0", "_score": 1, "_source": {} } ] }}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家的支持。


  • 上一条:
    详解python3安装pillow后报错没有pillow模块以及没有PIL模块问题解决
    下一条:
    Python中如何导入类示例详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客