python—简单数据抓取七(采取蘑菇API代理设置scrapy的代理IP池并利用redis形成队列依次使用,利用ip池访问网页并将scrapy爬取转移到items的数据存入到数据库)

学习目标:

Python学习二十七—简单数据抓取七


学习内容:

1、采取蘑菇API代理设置scrapy的代理IP池并利用redis形成队列依次使用
2、利用ip池访问网页并将scrapy爬取转移到items的数据存入到数据库
3、注意事项


1、采取蘑菇API代理设置scrapy的代理IP池并利用redis形成队列依次使用

  • 以安居客为例(安居客会根据访问的IP地址对用户进行限制)
    1、首先创建一个爬取安居客全站的项目
  • 在cmd窗口cd到项目需要保存的位置,输入:scrapy startproject fangzi,创建fangzi项目
  • cd到fangzi项目里面,然后输入:scrapy genspider anjuke tianjin.anjuke.com/sale/p1/?from=navigation,创建anjuke爬虫
    在这里插入图片描述
  • 创建run运行文件
    在这里插入图片描述

2、创建利用蘑菇代理API代理获取IP地址池的get_ip.py文件
在这里插入图片描述

import time
import requests
import redis

# 在死循环中不断获取API代理的IP地址
while True:
    # 连接redis数据库
    r = redis.Redis(host='127.0.0.1', port=6379, db=0)
    # 判断数据库的IP个数是否满
    if r.llen('proxy_ip') < 10:
        # 获取API链接中信息,并且转换为json数据
        source = requests.get('蘑菇代理的API链接').json()
        # 根据获取的API信息,拿出需要的IP地址和port端口
        for i in source['msg']:
            # 按照格式将两个信息进行拼接
            ip = i['ip'] + ':' + i['port']
            print(ip)
            # 插入到redis数据库中
            r.lpush('proxy_ip', ip)
    else:
        # 延迟3秒,之后打印IP池的状态
        time.sleep(3)
        print('代理IP池已满!!!')

3、在middlewares.py文件中进行相关的请求与返回的配置

  • middlewares文件中需要连接数据库,在最前端输入如下:
import redis 
r = redis.Redis(host='127.0.0.1', port=6379, db=0)
  • middlewares文件中网页访问链接的时候带上proxy,找到process_request输入如下:
def process_request(self, request, spider):
# ip地址从redis数据库中取出,并转码为utf8
    ip = r.lpop('proxy_ip').decode('utf8')
    print(ip)
    # 请求链接时带上该proxy
    request.meta['proxy'] ='https://' + ip

    return None
  • middlewares文件中网页访问返回的信息,在response中进行处理,找到process_response输入如下:
def process_response(self, request, response, spider):
    # Called with the response returned from the downloader.
    # 判断返回信息是否为200正常状态
    if response.status == 200:
    # 同时根据实际页面的大小为700判断是否返回的是正常页面,可以在请求的页面上用len方法获取到大小
        if len(response.text) > 750000:
        # 将正常请求网页的链接进行分割取出ip和port回收到redis数据库
            ip = request.meta['proxy'].split('//')[-1]
            # 将正常能用的ip和port重新插回到redis数据库
            r.lpush('proxy_ip', ip)
            # 并返回正常的信息
            return response
	# 重回调度队列
    return request
  • middlewares文件中如果请求不到正确的网页信息,就到process_exception,重新获取新的IP进行新的请求,输入如下:
def process_exception(self, request, exception, spider):
    # Called when a download handler or a process_request()
    # (from other downloader middleware) raises an exception.

    ip = r.rpop('proxy_ip').decode('utf8')
    print(ip)
    request.meta['proxy'] = 'https://' + ip
    # Must either:
    # - return None: continue processing this exception
    # - return a Response object: stops process_exception() chain
    # - return a Request object: stops process_exception() chain
    return request

4、在setting.py文件中,进行相关的配置

  • 请求下载页面内容的延迟
DOWNLOAD_DELAY = 2
  • 打开代理IP的设置
DOWNLOADER_MIDDLEWARES = {
   'fangzi.middlewares.FangziDownloaderMiddleware': 543,
}

2、利用ip池访问网页并将scrapy爬取转移到items的数据存入到数据库

1、利用设置好的IP地址池,来请求安居客网页避免因为同一个IP地址频繁访问而被封掉

import scrapy
from fangzi.items import FangziItem

class AnjukeSpider(scrapy.Spider):
    name = 'anjuke'

    # 利用代理ip以及携带header头访问安居客网页,并且关系到下面的get_ip方法,start_requests方法获取的东西都传给get_ip方法
    def start_requests(self):
        yield scrapy.Request('https://tianjin.anjuke.com/sale/p1/?from=navigation', self.first, headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36'
        }, dont_filter=True)
    # 从安居客二手房的第一页获取到所有页面的信息,然后抓取全站的房源信息
    def first(self, response):
        one_type = response.xpath('//*[@id="__layout"]/div/section/section[2]/section/div[1]/section/ul[2]/li/a/@href').extract()[1:]
        for hrefs in one_type:
            yield scrapy.Request(hrefs, self.get_href)

    def get_href(self, response):
        two_type = response.xpath('//*[@id="__layout"]/div/section/section[2]/section/div[1]/section/ul[3]/li/a/@href').extract()[1:]
        for hrefs in two_type:
            yield scrapy.Request(hrefs, self.get_page)

    def get_page(self, response):
         max_page = response.xpath('//li[@class="page-item last"]/a/text()').extract_first('1')
         for page in range(1, int(max_page)+1):
             last_href = response.url.replace('/?', '/p'+str(page)+'/?')
             yield scrapy.Request(last_href, self.get_ip)

    def get_ip(self, response):
        # 实例化item购物车
        item = FangziItem()
        # 提取xpath的公共部分
        base = response.xpath('//div[@class="property"]')
        for i in base:
            # xpath到房源信息的标题
            title = i.xpath('a/div[2]/div[1]/div[1]/h3/text()').extract_first()
            # xpath到房源信息的房型
            house_type = ''.join(i.xpath('a/div[2]/div[1]/section/div[1]/p[1]/span/text()').extract())
            # xpath到房源信息的面积
            house_size = i.xpath('a/div[2]/div[1]/section/div[1]/p[2]/text()').extract_first().strip()
            print(title, house_type, house_size)
            # 将获取的三个信息合并成列表,并根据','分割
            lists = 'title,house_type,house_size'.split(',')
            # 将获取的内容插入到item中,这里用了一个eval的方法
            for i in lists:
                item[i] = eval(i)
            yield item
  • 同时item.py文件的内容
import scrapy


class FangziItem(scrapy.Item):
    title = scrapy.Field()
    house_type = scrapy.Field()
    house_size = scrapy.Field()

2、将scrapy项目连接到数据库,并将获取的信息存入到数据库中

  • 在settings.py文件中进行数据库相关信息的配置,在最后输入如下:
DB_USER = 'root'
DB_PWD = '1234'
HOST = '127.0.0.1'
DB_NAME = 'anjuke'
  • 记得将setting文件中的打开
 ITEM_PIPELINES = {
   'fangzi.pipelines.FangziPipeline': 300,
}
  • 在pipliens.py文件中获取item购物车中的信息,并存入到mysql数据库中:
 import pymysql


class FangziPipeline(object):
    # 初始化相关的数据库配置信息
    def __init__(self, user, password, host, db_name):
        self.user = user
        self.password = password
        self.host = host
        self.db_name = db_name

    # 利用修饰符在不形成实例化的情况下直接调用settings文件中数据库配置信息
    @classmethod
    def from_crawler(cls, crawler):
        return cls(user=crawler.settings.get('DB_USER'), password=crawler.settings.get('DB_PWD'), host=crawler.settings.get('HOST'), db_name=crawler.settings.get('DB_NAME'))

    def open_spider(self, crawler):
        # 该方法继承类的默认属性,并得到数据库配置信息,连接到mysql数据库
        self.db = pymysql.connect(user=self.user, password=self.password, host=self.host, db=self.db_name, charset='utf8')
        # 测试数据库的连通性
        self.db.ping(reconnect=True)
        # 使用cursor()方法获取数据库的操作游标
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        # 将item中的数据插入到设置好的mysql数据库中
        sql = "insert into anjuke(title, house_type, house_size) VALUE ('{}', '{}', '{}')".format(item['title'], item['house_type'], item['house_size'])
        # 执行该插入数据命令
        self.cursor.execute(sql)
        # 提交执行
        self.db.commit()
        return item

    def close_spider(self, spider):
        # 关闭数据库
        self.db.close()

3、注意事项

1、ip池利用了redis数据库
2、获取的数据存储利用了mysql数据库
3、运行时,首先运行get_ip.py文件,方便获取新鲜的ip地址,再运行run.py文件
4、抓取安居客全站的信息时,注意各个分类以及相关最大页数的提取

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值