38-Scrapy-Redis构建-有缘网分布式爬虫项目【网络学习】

1、分析

爬取有缘网上:79b95527cd2a55cb94bef1b39aba49e11ae.jpg

1-1、网址变化

第一页网址:http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p1/  

第二页就是变为p2,第三页就是变为p3     【共有2206423人,大数据】

1-2、网页信息的获取

首先获取所有该条件下的所有页的链接;再获取每页上每个女生的详细信息(用户名、年龄、头像图片链接、相册链接、内心独白、籍贯、学历、爱好)。

爬取每个女生的信息:

  • 用户名               //dl[@class=”personal_cen”]//div[@class=”main”]/strong/text()
  • 年龄                   //dl[@class=”personal_cen”]//p//text()     需要age.split(“ ”)[2]
  • 头像图片链接      //dl[@class=”personal_cen”]/dt/img/@src
  • 相册链接            //div[@class=”ph_show”]/ul/li/a/img/@src
  • 内心独白            //div[@class=”pre_data”]/ul/li/p/text()    需要content.strip()
  • 籍贯                   //div[@class=”pre_data”]/ul/li[2]//ol[1]/li[1]/span/text() 
  • 学历                   //div[@class=”pred_data”]/ul/li[3]//ol[2]/li[2]/span/text()
  • 爱好                   //dl[@class=”personal_cen”]//ol/li/text()    返回是个列表lists,需要”,”.join(lists).replace(“ ”,””)

2、基于crawlspider类的爬虫

【2中的步骤是基于crawlspider类】   (还不是分布式爬虫)

【代码文件夹(youyuan)】

2-1、基础操作

C:\Users\Administrator\Desktop>scrapy startproject youyua     创建有缘网的项目
C:\Users\Administrator\Desktop>cd youyuan
C:\Users\Administrator\Desktop\youyuan>scrapy genspider -t crawl demo youyuan.com      创建一个基于crawlspider的爬虫类,名称为demo

2-2、在items.py文件中编辑item

 在上述要爬取的女生信息中,首先设置基础信息,其次增加source_url个人主页网址(即为response_url)和source数据来源网站(source)。

【注:增加source_url和source是为了知道爬取的更详细信息】

from scrapy import Item,Field

class YouyuanItem(Item):
    username=Field()  #用户名
    age=Field()  #年龄
    header_url=Field()  #头像图片链接
    image_url=Field()  #相册图片的链接
    content=Field()  #内心独白
    location=Field()  #籍贯
    education=Field()  #学历
    hobby=Field()  #兴趣爱好
    source_url=Field() # 个人主页 直接response.url即可
    source=Field()  #数据来源网站 youyuan

2-3、在demo.py文件中编辑“基于Crawlspider类的爬虫”

# -*- coding: utf-8 -*-
import re
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from youyuan.items import YouyuanItem

class DemoSpider(CrawlSpider):
    name = 'demo'
    allowed_domains = ['youyuan.com']
    start_urls = ['http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p1/']
    
    #匹配规则
    #第一级匹配规则:北京市18-25岁女性的每一页链接匹配规则
    page_links=LinkExtractor(allow=(r"youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p\d+/"))
    #第二级匹配规则:每个女性个人主页的匹配规则
    profile_links=LinkExtractor(allow=(r"youyuan.com/\d+-profile/"))

    rules = (
        Rule(page_links),
        Rule(profile_links,callback='parse_item')
    )
    #没有写callback回调函数,默认follow就是True,写了callback回调函数,默认follow就是False

    def parse_item(self, response):  #回调函数,用于解析每个女性个人主页
        item=YouyuanItem()
        item['username']=response.xpath('//dl[@class="personal_cen"]//div[@class="main"]/strong/text()').extract()[0]
        age=response.xpath('//dl[@class="personal_cen"]//dd/p/text()').extract()[0]
        item['age']=re.findall(r"(\d+)岁",age)[0]
        item['header_url']=response.xpath('//dl[@class="personal_cen"]/dt/img/@src').extract()[0]
        item['image_url']=response.xpath('//div[@class="ph_show"]/ul/li/a/img/@src').extract()  #有多个相册,直接返回列表
        item['content']=response.xpath('//div[@class="pre_data"]/ul/li/p/text()').extract()[0]
        item['location']=response.xpath('//div[@class="pre_data"]/ul/li[2]//ol[1]/li[1]/span/text()').extract()[0]
        item['education']=response.xpath('//div[@class="pred_data"]/ul/li[3]//ol[2]/li[2]/span/text()').extract()[0]
        hobby=response.xpath('//dl[@class="personal_cen"]//ol/li/text()').extract()
        item['hobby']=",".join(hobby).replace(" ","")
        item['source_url']=response.url
        item['source']='youdao'
        yield item

2-4、编写pipelines.py管道文件,将数据存储到youyuan.json文件中

(1)首先在settings.py中打开pipeline:

ITEM_PIPELINES = {
    'youyuan.pipelines.YouyuanPipeline': 300,
}

(2)然后在pipelines.py中编辑处理item的管道:

import json
class YouyuanPipeline(object):
    def __init__(self):
        self.filename=open("youyuan.json",'w',encoding='utf-8')
    def process_item(self, item, spider):
        text=json.dumps(dict(item),ensure_ascii=False)+'\n'
        self.filename.write(text)
        return item

    def close_spider(self,spider):
        self.filename.close()

2-5、运行的结果

C:\Users\Administrator\Desktop\youyuan>scrapy crawl demo                【得到“youyuan.json”结果】

2-6、将item数据存放到数据库中    ===>编辑settings.py文件

在settings.py中加pipeline(来自scrapy_redis),并进一些关于redis的操作:

ITEM_PIPELINES = { 
    'youyuan.pipelines.YouyuanPipeline': 300, 
    'scrapy_redis.pipelines.RedisPipeline':400, 
}

#使用scrapy_redis中的去重组件,不使用scrapy默认的去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

#使用scrapy_redis中的调度器组件,不使用scrapy默认的调度器
#scrapy中默认的调度器是:直接把请求放到队列里,然后直接交给下载器
#scrapy-redis是:先把请求给redis,在redis中做去重判断,然后交还给调度器,调度器再把请求放到队列里,然后交给下载器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

#允许暂停,redis请求记录不丢失
SCHEDULER_PERSIST = True

需要先打开redis数据库:C:\Users\Administrator\Desktop>redis-server

然后运行爬虫代码:C:\Users\Administrator\Desktop\youyuan>scrapy crawl demo

此时利用redis-desktop-Manager中可以看到我设置的demo数据库,里面存放的是数据,如下图:

38-Scrapy-Redis构建-有缘网分布式爬虫项目【网络学习】_第1张图片

【总结:将数据保存到redis数据库中,很简单。

按照传统的Spider或Crawlspider类的爬虫方法,最后在settings.py文件中打开scrapy_redis管道以及设置一些关于redis的操作,即可。

再运行代码就可以将数据存放到redis数据库】

3、把【2基于crawlspider类的爬虫】改为【基于RedisCrawlSpider类的分布式爬虫】    (是分布式爬虫)

【代码文件夹(youyuan1)】

【注:youyuan1先是直接拷贝的youyuan文件夹,在此基础上进行修改】   【小细节:一些代码中原来为youyuan将其修改为youyuan1】

3-1、因为修改为分布式,所以爬虫类发生变化(由CrawlSpider变为RedisCrawlSpider)

修改demo.py中的爬虫类,以及一些小细节【见蓝色处】

# -*- coding: utf-8 -*-
import re
import scrapy
from scrapy.linkextractors import LinkExtractor
#from scrapy.spiders import CrawlSpider
from scrapy.spiders import Rule
from scrapy_redis.spiders import RedisCrawlSpider  #引入RedisCrawlSpider类
from youyuan.items import YouyuanItem

#class DemoSpider(CrawlSpider):
class DemoSpider(RedisCrawlSpider):
    name = 'demo'
    #allowed_domains = ['youyuan.com']
    #start_urls = ['http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p1/']
    redis_key = "demospider:start_urls"

    #动态获取域名
    def __init__(self,*args,**kwargs):
        domain=kwargs.pop('domain','')
        self.allowed_domains=filter(None,domain.split(','))
        super(DemoSpider,self).__init__(*args,**kwargs)

    #第一级匹配规则:北京市18-25岁女性的每一页链接匹配规则
    page_links=LinkExtractor(allow=(r"youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p\d+/"))
    #第二级匹配规则:每个女性个人主页的匹配规则
    profile_links=LinkExtractor(allow=(r"youyuan.com/\d+-profile/"))

    rules = (
        Rule(page_links),
        Rule(profile_links,callback='parse_item')
    )
    #没有写callback回调函数,默认follow就是True,写了callback回调函数,默认follow就是False

    def parse_item(self, response):
        item=YouyuanItem()
        item['username']=response.xpath('//dl[@class="personal_cen"]//div[@class="main"]/strong/text()').extract()[0]
        age=response.xpath('//dl[@class="personal_cen"]//dd/p/text()').extract()[0]
        item['age']=re.findall(r"(\d+)岁",age)[0]
        item['header_url']=response.xpath('//dl[@class="personal_cen"]/dt/img/@src').extract()[0]
        item['image_url']=response.xpath('//div[@class="ph_show"]/ul/li/a/img/@src').extract()  #有多个相册,直接返回列表
        item['content']=response.xpath('//div[@class="pre_data"]/ul/li/p/text()').extract()[0]
        item['location']=response.xpath('//div[@class="pre_data"]/ul/li[2]//ol[1]/li[1]/span/text()').extract()[0]
        item['education']=response.xpath('//div[@class="pred_data"]/ul/li[3]//ol[2]/li[2]/span/text()').extract()[0]
        hobby=response.xpath('//dl[@class="personal_cen"]//ol/li/text()').extract()
        item['hobby']=",".join(hobby).replace(" ","")
        item['source_url']=response.url
        item['source']='youdao'
        yield item

        # 可以重写Spider类的start_requests方法,附带Cookie值,发送POST请求
        def start_requests(self):
            for url in self.start_urls:
                yield scrapy.FormRequest(url, cookies=self.cookies, callback=self.parse_page)

        # 处理响应内容
        def parse_page(self, response):
            print(response.url)
            with open("renern3.html", "w") as filename:
                filename.write(response.body)

3-2、在settings.py文件中加“scrapy-redis请求队列形式”以及slave爬虫端需要访问master端redis的“REDIS_HOST”和“REDIS_PORT”

#默认的scrapy-redis请求队列形式(按优先级顺序)
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"

REDIS_HOST="192.168.21.63"
REDIS_PORT=6379

3-3、运行该分布式爬虫

(1)slaver端爬虫(师弟电脑)运行:C:\Users\Administrator\Desktop\youyuan1>scrapy runspider demo.py  

此时处于等待状态:1a4414e008f373ad4d2cfddd6a2db850b7c.jpg

(2)master端redis数据库(我的电脑)运行:lpush demospider:start_urls http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0/p1/

f1625bcb2cae20b39dc88d1d379015839f5.jpg

(3)此时slaver端爬虫(师弟电脑)开始爬虫!!!

(4)并且master端redis数据库中能查看到数据!!!

 

【进阶】将存储到redis数据中的item数据存储到mysql数据库中   【可以单独使用】

(1)首先在mysql中建立数据库、数据表、字段,

(2)再在文件youyuan1/process_item_for_mysql.py编写如下代码:

import redis
import pymysql
import json

def process_item():
    #创建redis数据库连接
    rediscli=redis.Redis(host="127.0.0.1",port=6379,db=0)
    #创建MySQL数据库连接  localhost就是127.0.0.1
    mysqlcli=pymysql.connect(host="127.0.0.1",port=3306,user='root',passwd="12345678",db="youyuan")

    offset=0
    while True:
        # 将数据从redis里pop出来
        source, data = rediscli.blpop("demo:items")
        item = json.loads(data)
        #创建mysql操作游标对象,可以执行mysql语句
        cursor=mysqlcli.cursor()
        try:
            cursor.execute("insert into beijing_18_25_mm (username,age,header_url,images_url,content,location,education, hobby,source_url,source,spidername) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"%(item['username'],item['age'],item['header_url'],item['images_url'],item['content'],item['location'],item['education'],item['hobby'],item['source_url'],item['source'],item['spidername']))
            #提交事务
            mysqlcli.commit()
            #关闭游标
            cursor.close()
            offset+=1
        except:
            mysqlcli.rollback()
            cursor.close()
process_item()  #可以单独执行

转载于:https://my.oschina.net/pansy0425/blog/3099583

你可能感兴趣的:(38-Scrapy-Redis构建-有缘网分布式爬虫项目【网络学习】)