Scrapy框架学习

本文围绕Scrapy框架展开学习,涵盖基础安装、命令使用、配置文件设置等内容。介绍了创建项目、使用Scrapy Shell的方法,深入讲解了pipeline管道、存储数据库、下载图片、模拟登陆与分页等操作,还对相关参数进行了解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Scrapy框架学习

文章目录

1.基础

1.安装

pip install scrapy

2. 常见的命令

scrapy startproject: 创建新的爬虫项目。

scrapy genspider: 创建新的爬虫。

scrapy crawl: 运行爬虫。

scrapy shell: 启动 Scrapy shell,可以在交互式命令行中测试爬虫代码。

scrapy view: 打开给定 URL 的页面,方便调试。

scrapy fetch: 使用 Scrapy 的下载器下载给定 URL 的页面。
#配置日志打印级别 settings.py
L0G_LEVEL='ERROR' #当有报错ERROR了会执行打印
或者用以下命令启动
scrapy crawl dzx -s LOG_LEVEL=ERROR 

pipelines.py——>管道,保存数据
settings.py——>设置文件,UA,启动管道
spiders
——>自己定义的spider的文件夹

3、配置settings文件

  • ROBOTSTXT_OBEY = False

    robots是一种反爬协议。在协议中规定了哪些身份的爬虫无法爬取的资源有哪些。

    在配置文件中setting,取消robots的监测:

  • 在配置文件中配置全局的UA:USER_AGENT=‘xxxx’

  • 在配置文件中加入日志等级:LOG_LEVEL = ‘ERROR’ 只输出错误信息

    其它日志级别

    • CRITICAL 严重错误
    • ERROR 错误
    • WARNING 警告
    • INFO 消息
    • DEBUG 调试

image-20230919204633965

2.开始

1.创建第一个项目

首先在目标文件夹下打开cmd或者终端

scrapy startproject duanzhi(项目名字自定义)
cd duanzhi
scrapy genspider dzx duanzixing.com 

image-20230919204329743

image-20230919204358812

设置一下输出日志 当有报错ERROR了会执行打印

image-20230919204716206

写一部分代码来观察

class DzxSpider(scrapy.Spider):
    name = "dzx"
    # allowed_domains = ["duanzixing.com"]
    start_urls = ["https://duanzixing.com"]

    def parse(self, response, **kwargs):
        print(response)
        # 获取响应的内容
        # print(response.text)
        # 当前响应的url
        print('response.url:', response.url)
        # 当前响应对应的请求的url
        print('response.request.url:', response.request.url)
        # 响应头
        print('response.headers:', response.headers)
        # 响应的请求头
        print('response.request.headers:', response.request.headers)
        # 响应体
        print('response.body:', response.body)
        # 返回响应的内容
        print('response.text:', response.text)
        # 响应的状态码
        print('response.status:', response.status)
        # 获取响应的json数据 如果响应的内容不是json格式的数据,会报错
        # print('response.json():', response.json())
        
1.观察网页

image-20230919211800212

image-20230919211843983

可以得到

标题正文

2.用以前的方式进行获取
import requests
from lxml import etree

url = "https://duanzixing.com/"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
}

res = requests.get(url, headers=headers)

html = etree.HTML(res.text)

# 获取所有的段子
excerpt_list = html.xpath('/html/body/section/div/div/article')
# print(len(excerpt_list))
for tree in excerpt_list:
    title = tree.xpath('./header/h2/a/text()')
    text = tree.xpath('./p[@class="note"]/text()')
    print(title)
    print(text)

image-20230919212233825

3.用scrapy
    def parse(self, response, **kwargs):
        excerpt_list=response.xpath('/html/body/section/div/div/article')
        data={}
        for tree in excerpt_list:
            title = tree.xpath('./header/h2/a/text()').extract()
            text = tree.xpath('./p[@class="note"]/text()').extract()
            print(title)
            print(text)

image-20230919212454370

3.了解scrapyShell

https://duanzixing.com

4.settings.py中的设置信息

3.1 为什么项目中需要配置文件

在配置文件中存放一些公共变量,在后续的项目中方便修改,如:本地测试数据库和部署服务器的数据库不一致

3.2 配置文件中的变量使用方法
  1. 变量名一般全部大写
  2. 导入即可使用
3.3 settings.py中的重点字段和含义
  • USER_AGENT 设置ua

  • ROBOTSTXT_OBEY 是否遵守robots协议,默认是遵守

  • CONCURRENT_REQUESTS 设置并发请求的数量,默认是16个

  • DOWNLOAD_DELAY 下载延迟,默认无延迟 (下载器在从同一网站下载连续页面之前应等待的时间(以秒为单位)。这可以用来限制爬行速度,以避免对服务器造成太大影响)

  • COOKIES_ENABLED 是否开启cookie,即每次请求带上前一次的cookie,默认是开启的

  • DEFAULT_REQUEST_HEADERS 设置默认请求头,这里加入了USER_AGENT将不起作用

  • SPIDER_MIDDLEWARES 爬虫中间件,设置过程和管道相同

  • DOWNLOADER_MIDDLEWARES 下载中间件

  • LOG_LEVEL 控制终端输出信息的log级别,终端默认显示的是debug级别的log信息

    • LOG_LEVEL = “WARNING”
      • CRITICAL 严重
      • ERROR 错误
      • WARNING 警告
      • INFO 消息
      • DEBUG 调试
  • LOG_FILE 设置log日志文件的保存路径,如果设置该参数,终端将不再显示信息

    LOG_FILE = “./test.log”

  • 其他设置参考:https://www.jianshu.com/p/df9c0d1e9087

5.pipeline管道的深入使用

1.代码配置
class ITSpider(scrapy.Spider):
    name = 'ITSpider'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://duanzixing.com/page/1/']

    # 通过终端写入文件的方式
    def parse(self, response):
        article_list = response.xpath('/html/body/section/div/div/article')
        # 创建列表, 存储数据
        all_data = []
        for article in article_list:
            title = article.xpath('./header/h2/a/text()').extract_first()
            con = article.xpath('./p[2]/text()').extract_first()
            dic = {
                'title': title,
                'con': con
            }
            all_data.append(dic)
        return all_data
  • 终端命令

    scrapy crawl 爬虫名称-o 文件名.csv

    scrapy crawl ITSpider -o ITSpider.csv

    将文件存储到ITSpider.csv 文件中

2.开启管道

pipeline中常用的方法:

  1. process_item(self,item,spider):实现对item数据的处理
  2. open_spider(self, spider): 在爬虫开启的时候仅执行一次
  3. close_spider(self, spider): 在爬虫关闭的时候仅执行一次
3.进行管道测试 pipelines.py
class DuanzhiPipeline:

    # 在爬虫开启的时候仅执行一次
    def open_spider(self, item):
        print("爬虫开始了")
        # 进行文件的打开
        self.f = open('duanzhi.txt', 'w', encoding='utf-8')

    # 实现对item数据的处理
    def process_item(self, item, spider):
        self.f.write(item['title'] + '\n')
        self.f.write(item['text'] + '\n')
        return item

    # 在爬虫关闭的时候仅执行一次
    def close_spider(self, item):
        print("爬虫结束了")
        self.f.close()
4.总结代码
1.dzx.py
    def parse(self, response, **kwargs):
        item = DuanzhiItem()
        excerpt_list = response.xpath('/html/body/section/div/div/article')
        for tree in excerpt_list:
            title = tree.xpath('./header/h2/a/text()').extract()
            text = tree.xpath('./p[@class="note"]/text()').extract()
            item['title'] = title
            item['text'] = text
            yield item
2.items.py
class DuanzhiItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    text = scrapy.Field()
3.pipelines.py
class DuanzhiPipeline:

    # 在爬虫开启的时候仅执行一次
    def open_spider(self, item):
        print("爬虫开始了")
        # 进行文件的打开
        self.f = open('duanzhi.txt', 'w', encoding='utf-8')

    # 实现对item数据的处理
    def process_item(self, item, spider):
        if item['title'] and item['text']:
            self.f.write(item['title'][0] + '\n')
            self.f.write(item['text'][0] + '\n')
        return item

    # 在爬虫关闭的时候仅执行一次
    def close_spider(self, item):
        print("爬虫结束了")
        self.f.close()
4.运行并产生duanzhi.txt

image-20230919221631883

image-20230919221653448

没有文件产生别文件settings.py 打开管道

image-20230919223320970

5.动态数据实操(新发地)
看网页分析

image-20230919224632808

image-20230919224652855

可以得知是post 请求 且数据为json且存储在list下面

我们只需获取以下数据:

prodName: “大白菜”

avgPrice: “0.53”

unitInfo: “斤”

pubDate: “2023-09-19 00:00:00”

实战开始:

1.创建爬虫
scrapy startproject xingfadi
cd xingdadi
scrapy genspider xfd xinfadi.com.cn
2.setting.py

设置日志

LOG_LEVEL = "WARNING"

设置robots

ROBOTSTXT_OBEY =False

打开管道

ITEM_PIPELINES = {
   "xingfadi.pipelines.XingfadiPipeline": 300,
}
3.xfd.py
import scrapy
from xingfadi.items import XingfadiItem


class XfdSpider(scrapy.Spider):
    name = "xfd"
    # allowed_domains = ["xinfadi.com.cn"]
    start_urls = ["http://www.xinfadi.com.cn/getPriceData.html"]

    def parse(self, response):
        item = XingfadiItem()
        html = response.json()
        all_list = html["list"]
        for i in all_list:
            prodName = i["prodName"]
            avgPrice = i["avgPrice"]
            unitInfo = i["unitInfo"]
            pubDate = i["pubDate"]
            item["prodName"] = prodName
            item["avgPrice"] = avgPrice
            item["unitInfo"] = unitInfo
            item["pubDate"] = pubDate
            yield item
4.items.py
import scrapy


class XingfadiItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    prodName = scrapy.Field()
    avgPrice = scrapy.Field()
    unitInfo = scrapy.Field()
    pubDate = scrapy.Field()
5.pipelines.py
class XingfadiPipeline:
    def open_spider(self, spider):
        print("爬虫开始了")
        self.f = open("新发地价格.txt", "w", encoding="utf-8")

    def process_item(self, item, spider):
        if item["prodName"] and item["avgPrice"] and item["unitInfo"] and item["pubDate"]:
            self.f.write(
                item["prodName"] + ":    " + item["avgPrice"] + item["unitInfo"] + "     时间:" + item["pubDate"] + "\n")

        return item

    def close_spider(self, spider):
        print("爬虫结束了")
        self.f.close()
6.出结果

image-20230919225532926

6.总结

1.创建好项目以后先要配置setting里面的内容

2.无论是post还是get请求都可以直接写

3.以前需要导入的包已经自动导入不需要再次导入

4.items.py 的属性要和 爬虫.py 里面的属性一一对应否则会报错

5.pipelines.pt 一定要if 在进行写入否则不会成功 我也不知道为什么😄

乱写👌

5.scrapy存数据库

1.MYSQL

1.数据库建表
create database spider;
use spider;
CREATE TABLE dzx (
    title VARCHAR(255),
    text TEXT
);
2.pipelines.py

基于第一个案例的dzx来说进行一个把数据存储到数据库中

import pymysql


class DuanzhiPipeline:
    def open_spider(self, spider):
        # 在爬虫开启的时候仅执行一次
        print("爬虫开始了")
        self.db = pymysql.connect(host='localhost', user='root', password='1234',
                                  port=3306, db='spider', charset='utf8')
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        # 实现对item数据的处理
        try:
            title = item['title']
            text = item['text']
            # 构建SQL语句
            sql = "INSERT INTO dzx (title, text) VALUES (%s, %s)"
            # 执行SQL语句,并传递参数
            self.cursor.execute(sql, (title, text))
            # 提交事务
            self.db.commit()
        except Exception as e:
            # 处理数据库出错的情况
            print("数据库出错:" + str(e))
            # 回滚事务
            self.db.rollback()
        return item

    def close_spider(self, spider):
        # 在爬虫关闭的时候仅执行一次
        print("爬虫结束了")
        self.cursor.close()
        self.db.close()
3.运行查看结果

image-20230920180314611

image-20230920180339626

4.总结

sql 语句要正确 尤其是对添加内容的时候

2.MongoDB

pipelines.py

用上面的新发地的案例进行修改

from pymongo import MongoClient

class XingfadiPipeline:
    def open_spider(self, spider):
        print("爬虫开始了")
        # 连接数据库
        self.con = MongoClient(host='127.0.0.1', port=27017)
        # 创建库
        self.db = self.con['spider']
        # 创建集合
        self.myset = self.db['xfd']


    def process_item(self, item, spider):
        # 把item转换成字典
        result = self.myset.insert_one(dict(item))
        print(result.inserted_id)
        return item

    def close_spider(self, spider):
        print("爬虫结束了")
        self.con.close()

image-20230920182823849

对于MongoDB来说 无需提前进行对数据库的创建

但有必要进行一次测试连接

from pymongo import MongoClient

# 连接数据库
client = MongoClient(host='127.0.0.1', port=27017)

# 测试连接
try:
    client.admin.command('ping')
    print("成功连接到MongoDB!")
except Exception as e:
    print("连接失败:", e)

# 关闭连接
client.close()
运行不报错有没看见数据?

对于pycharm来说 刷新看一下或者打开勾选选择数据库

image-20230920183025807

6.scrapy下载图片

1.settings 设置

ITEM_PIPELINES = {
    "desk.pipelines.DeskPipeline": 300,
    "desk.pipelines.ImgPipeline": 400, # 图片下载
}

IMAGES_STORE = "./img" # 图片存储路径

1.要打开对应的下载图片的管道

2.要设置一个下载图片的存储地址

2.通用下载图片配置文件

import scrapy
from urllib.parse import urljoin


class ImgSpider(scrapy.Spider):
    name = 'img'
    # allowed_domains = ['desk.zol.com.cn/dongman']
    start_urls = ['http://desk.zol.com.cn/dongman/']

    def parse(self, resp, **kwargs):
        # 先抓取到每个图片详情的url
        url_list = resp.xpath('//ul[@class="pic-list2  clearfix"]/li/a/@href').extract()
        # 获取到url列表后 进行循环进行每一个url详情页的请求
        for url in url_list:
            # 因为抓取到的url并不完整,需要进行手动拼接
            # urljoin('https://desk.zol.com.cn/dongman/', '/bizhi/8301_103027_2.html')
            url = urljoin('https://desk.zol.com.cn/dongman/', url)
            # 拼凑完发现当前url中有下载exe的url,将其去除
            if url.find('exe') != -1:
                continue
            yield scrapy.Request(url, callback=self.parse_detail)

    # 对详情页进行解析
    def parse_detail(self, resp):
        # 获取当前详情页中最大尺寸图片的url
        max_img_url = resp.xpath('//dd[@id="tagfbl"]/a/@href').extract()
        # 判断当前最大图片的url地址,为倒数第二个,如果当前图片列表url长度小于2 则当前证明不是图片的url
        if len(max_img_url) > 2:
            max_img_url = urljoin('https://desk.zol.com.cn/', max_img_url[0])
            # 对url页面进行请求 获取最终大图的页面
            yield scrapy.Request(max_img_url, callback=self.parse_img_detail)

    def parse_img_detail(self, resp):
        # 解析出大图的url
        img_src = resp.xpath("//img[1]/@src").extract_first()
        return {'img_src': img_src}

img_src是固定的名称 或者可以自定义修改 ,要pipelines.py和img.py 传递的参数要一一对应

3.pipelines.py

from itemadapter import ItemAdapter
from scrapy.pipelines.images import ImagesPipeline
import scrapy

class DeskPipeline:
    def process_item(self, item, spider):
        return item
class Imgspipline(ImagesPipeline):
    # 1. 发送请求(下载图片, 文件, 视频,xxx)
    def get_media_requests(self, item, info):
      	# 获取到图片的url
        url = item['img_src']
        # 进行请求
        yield scrapy.Request(url=url, meta={"url": url})  # 直接返回一个请求对象即可

    # 2. 图片存储路径
    def file_path(self, request, response=None, info=None, *, item=None):
        # 当前获取请求的url的方式有2种
        # 获取到当前的url 用于处理下载图片的名称
        file_name = item['img_src'].split("/")[-1]  # 用item拿到url
        # file_name = request.meta['url'].split("/")[-1]  # 用meta传参获取
        return file_name

    # 3. 可能需要对item进行更新
    def item_completed(self, results, item, info):
        # print('results', results)
        for r in results:
            # 获取每个图片的路径
            print(r[1]['path'])
        return item  # 一定要return item 把数据传递给下一个管道

4.img.py

import scrapy
from urllib.parse import urljoin


class ImgSpider(scrapy.Spider):
    name = 'img'
    # allowed_domains = ['desk.zol.com.cn/dongman']
    start_urls = ['http://desk.zol.com.cn/dongman/']

    def parse(self, resp, **kwargs):
        # 先抓取到每个图片详情的url
        url_list = resp.xpath('//ul[@class="pic-list2  clearfix"]/li/a/@href').extract()
        # 获取到url列表后 进行循环进行每一个url详情页的请求
        for url in url_list:
            # 因为抓取到的url并不完整,需要进行手动拼接
            # urljoin('https://desk.zol.com.cn/dongman/', '/bizhi/8301_103027_2.html')
            url = urljoin('https://desk.zol.com.cn/dongman/', url)
            # 拼凑完发现当前url中有下载exe的url,将其去除
            if url.find('exe') != -1:
                continue
            yield scrapy.Request(url, callback=self.parse_detail)

    # 对详情页进行解析
    def parse_detail(self, resp):
        # 获取当前详情页中最大尺寸图片的url
        max_img_url = resp.xpath('//dd[@id="tagfbl"]/a/@href').extract()
        # 判断当前最大图片的url地址,为倒数第二个,如果当前图片列表url长度小于2 则当前证明不是图片的url
        if len(max_img_url) > 2:
            max_img_url = urljoin('https://desk.zol.com.cn/', max_img_url[0])
            # 对url页面进行请求 获取最终大图的页面
            yield scrapy.Request(max_img_url, callback=self.parse_img_detail)

    def parse_img_detail(self, resp):
        # 解析出大图的url
        img_src = resp.xpath("//img[1]/@src").extract_first()
        return {'img_src': img_src}

5.总结

1.对应最后的传参一点要对应好相对的元素

2.记得要设置好存储图片的路径以及打开对应的管道

3.报错多问G哥

7.scrapy模拟登陆&分页

1.回顾之前的模拟登陆的方法

1 requests模块模拟登陆?
  1. 直接携带cookies请求页面
  2. 找url地址,发送post请求存储cookie
2 selenium模拟登陆?
  1. 找到对应的input标签,输入文本点击登陆
3 scrapy模拟登陆
  1. 直接携带cookies
  2. 找url地址,发送post请求存储cookie
  3. 找到对应的form表单,自动解析input标签,自动解析post请求的url地址,自动带上数据,自动发送请求

2.scrapy携带cookies直接获取需要登陆后的页面

17k小说网

https://user.17k.com/
2.1 应用场景
  1. cookie过期时间很长,常见于一些不规范的网站
  2. 能在cookie过期之前把搜有的数据拿到
  3. 配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy发送请求之前先读取本地cookie
2.2 通过修改settings中DEFAULT_REQUEST_HEADERS携带cookie

settings.py

DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
  'Cookie': 'ASP.NET_SessionId=n4lwamv5eohaqcorfi3dvzcv; xiaohua_visitfunny=103174; xiaohua_web_userid=120326; xiaohua_web_userkey=r2sYazfFMt/rxUn8LJDmUYetwR2qsFCHIaNt7+Zpsscpp1p6zicW4w=='
}

注意:需要打开COOKIES_ENABLED,否则上面设定的cookie将不起作用

# Disable cookies (enabled by default)
COOKIES_ENABLED = False

xiaoshuo.py

import scrapy


class DengluSpider(scrapy.Spider):
    name = 'denglu'
    allowed_domains = ['17k.com']
    start_urls = ['https://user.17k.com/ck/user/mine/readList?page=1&appKey=2406394919']

    def parse(self, res):
        print(res.text)

局限性:

当前设定方式虽然可以实现携带cookie保持登录,但是无法获取到新cookie,也就是当前cookie一直是固定的

如果cookie是经常性变化,那么当前不适用

2.3 实现:重构scrapy的starte_rquests方法

scrapy中start_url是通过start_requests来进行处理的,其实现代码如下

def start_requests(self):
    cls = self.__class__
    if method_is_overridden(cls, Spider, 'make_requests_from_url'):
        warnings.warn(
            "Spider.make_requests_from_url method is deprecated; it "
            "won't be called in future Scrapy releases. Please "
            "override Spider.start_requests method instead (see %s.%s)." % (
                cls.__module__, cls.__name__
            ),
        )
        for url in self.start_urls:
            yield self.make_requests_from_url(url)
    else:
        for url in self.start_urls:
            yield Request(url, dont_filter=True)

所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写start_request方法并在其中手动添加上cookie

settings.py

import scrapy


class DengluSpider(scrapy.Spider):
    name = 'denglu'
    # allowed_domains = ['https://user.17k.com/ck/user/mine/readList?page=1']
    start_urls = ['https://user.17k.com/ck/user/mine/readList?page=1&appKey=2406394919']

    def start_requests(self):
        cookies = 'GUID=796e4a09-ba11-4ecb-9cf6-aad19169267d; Hm_lvt_9793f42b498361373512340937deb2a0=1660545196; c_channel=0; c_csc=web; accessToken=avatarUrl%3Dhttps%253A%252F%252Fcdn.static.17k.com%252Fuser%252Favatar%252F18%252F98%252F90%252F96139098.jpg-88x88%253Fv%253D1650527904000%26id%3D96139098%26nickname%3D%25E4%25B9%25A6%25E5%258F%258BqYx51ZhI1%26e%3D1677033668%26s%3D8e116a403df502ab; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2296139098%22%2C%22%24device_id%22%3A%22181d13acb2c3bd-011f19b55b75a8-1c525635-1296000-181d13acb2d5fb%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%2C%22first_id%22%3A%22796e4a09-ba11-4ecb-9cf6-aad19169267d%22%7D; Hm_lpvt_9793f42b498361373512340937deb2a0=1661483362'
        cookie_dic = {}
        for i in cookies.split(';'):
            v = i.split('=')
            cookie_dic[v[0]] = v[1]
        # {i.split('=')[0]:i.split('=')[1] for i in cookies_str.split('; ')}   # 简写
        for url in self.start_urls:
            yield scrapy.Request(url, cookies=cookie_dic)


    def parse(self, response):
        print(response.text)
注意:
  1. scrapy中cookie不能够放在headers中,在构造请求的时候有专门的cookies参数,能够接受字典形式的coookie
  2. 在setting中设置ROBOTS协议、USER_AGENT

3.scrapy.FormRequest发送post请求

我们知道可以通过scrapy.Request()指定method、body参数来发送post请求;那么也可以使用scrapy.FormRequest()来发送post请求

1 scrapy.FormRequest()的使用

通过scrapy.FormRequest能够发送post请求,同时需要添加fromdata参数作为请求体,以及callback

login_url = 'https://passport.17k.com/ck/user/login'      
yield scrapy.FormRequest(
            url=login_url, 
            formdata={'loginName': '17346570232', 'password': 'xlg17346570232'}, 
            callback=self.do_login
)
2 使用scrapy.FormRequest()登陆
1 思路分析
  1. 找到post的url地址:点击登录按钮进行抓包,然后定位url地址为https://www.xiaohua.com/Handler/Login.ashx
  2. 找到请求体的规律:分析post请求的请求体,其中包含的参数均在前一次的响应中
  3. 否登录成功:通过请求个人主页,观察是否包含用户名
2 代码实现如下:
import scrapy


class DlSpider(scrapy.Spider):
    name = "dl"
    allowed_domains = ["17k.com"]
    start_urls = ["https://user.17k.com/ck/user/myInfo/96139098?appKey=2406394919"]

    # 在请求start_urLs之前先登陆登陆以后就有了登录后的cookie此刻cookie是自动抓取的
    def start_requests(self):
        # 先在要在这里处理登陆的功能因为scrapy一执行自动调用当前方法
        # for url in self.start_urls:
        #     yield scrapy.Request(url=url)
        login_url = 'https://passport.17k.com/ck/user/login'
        # yield scrapy.Request(login_url, method='POST',
        #                      body='loginName=17346570232&password=xlg17346570232',
        #                      callback=self.do_start_requests)

        # FormRequest 是Scrapy发送POST请求的方法
        yield scrapy.FormRequest(login_url,
                                 formdata={
                                     'loginName': '17346570232',
                                     'password': 'xlg17346570232'
                                 },
                                 callback=self.do_start_requests)

    # 登录成功后再去请求start_urls
    def do_start_requests(self, response, **kwargs):
        for url in self.start_urls:
            yield scrapy.Request(url=url)

    def parse(self, response, **kwargs):
        print(response.text)

4.分页

1.分析

通过爬取段子页面的信息,学习如何实现翻页请求

地址:https://duanzixing.com/

思路分析:
  1. 获取首页的数据
  2. 寻找下一页的地址,进行翻页,获取数据
注意:
  1. 可以在settings中设置ROBOTS协议

    # False表示忽略网站的robots.txt协议,默认为True
    ROBOTSTXT_OBEY = False
    
  2. 可以在settings中设置User-Agent:

    # scrapy发送的每一个请求的默认UA都是设置的这个User-Agent
    USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
    
2.代码实现
import scrapy


class DzSpider(scrapy.Spider):
    name = "dz"
    allowed_domains = ["duanzixing.com"]
    start_urls = ["https://duanzixing.com/"]

    def parse(self, response, **kwargs):
        url = 'https://duanzixing.com/page/%d/'
        for i in range(1, 11):
            new_url = url % i
            # print(new_url)
            yield scrapy.Request(new_url, callback=self.parse_page, meta={
                'url': new_url})

    def parse_page(self, response, **kwargs):
        url = response.meta['url']
        article_list = response.xpath('//article[@class="excerpt"]')
        for article in article_list:
            data = {}
            title = article.xpath('./header/h2/a/text()').extract_first()
            con = article.xpath('./p[@class="note"]/text()').extract_first()
            data['title'] = title
            data['con'] = con
            print(data, url)
            yield data

5.参数解释

1.上诉代码:
  1. 中括号中的参数为可选参数
  2. callback:表示当前的url的响应交给哪个函数去处理
  3. meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
  4. dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
  5. method:指定POST或GET请求
  6. headers:接收一个字典,其中不包括cookies
  7. cookies:接收一个字典,专门放置cookies
  8. body:接收一个字典,为POST的数据
2.meta参数的使用
meta的形式:字典
meta的作用:meta可以实现数据在不同的解析函数中的传递

在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:

def parse(self,response):
    ...
    yield scrapy.Request(detail_url, callback=self.parse_detail,meta={"item":item})
...

def parse_detail(self,response):
    #获取之前传入的item
    item = resposne.meta["item"]
特别注意
  1. meta参数是一个字典
  2. meta字典中有一个固定的键proxy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值