scrapy如何GET和POST请求

post请求

class FanyiSpider(scrapy.Spider):
    name = 'fanyi'
    allowed_domains = ['baidu.com']
    # start_urls = ['https://fanyi.baidu.com/sug']
    # 引擎调度起来以后首先会从start_urls中提取起始url然后发起get请求,现在把这个属性注释掉,引擎就找不到起始url了,就不会发起默认的get请求
    # 如果要发起post请求,我们需要在这里重写爬虫的周期函数
    def start_requests(self):
        # 这个周期函数,下载器开始下载的时候开启
        print("下载器开始请求网络数据...")
        post_url = "https://fanyi.baidu.com/sug"
        # 创建表单
        data = {
            "kw":'a'
        }
        # 发起post请求
        yield scrapy.FormRequest(url=post_url,formdata=data,callback=self.parse_post) # 下载器对象不能由我们手动,我们需要将下载器创建流程返回给调度器,让调度器去同一调度

    # 定义post请求的回调函数
    def parse_post(self, response):
        print(111111111111111111111111111)
        print(response.text)

GET加POST请求

# -*- coding: utf-8 -*-
import scrapy
import pytesseract
from PIL import Image

class GushiwenSpider(scrapy.Spider):
    name = 'gushiwen'
    allowed_domains = ['gushiwen.org']
    start_urls = ['https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx']

    def parse(self, response):
        # 从response中取出两个token和一个验证码url
        # 取出两个token
        self.token1 = response.css("#__VIEWSTATE::attr(value)").extract()[0]
        self.token2 = response.css("#__VIEWSTATEGENERATOR::attr(value)").extract()[0]
        img_src = "https://so.gushiwen.org"+ response.css("#imgCode::attr(src)").extract()[0]
        # 【注意】scrapy自带的css方法可以直接通过css选择器选择页面中元素,如果我们要提取元素的某属性值直接在选择器后面加上“::attr(某属性)”,如果要提取内容,在选择器后面加上“::text”
        # 下载验证码
        # 调起来一个get下载器,来下载验证码
        yield scrapy.Request(url=img_src,callback=self.parse_code)

    # 封装一个回调函数,用于处理验证码的响应
    def parse_code(self,response):
        # response是验证码图片的响应数据
        with open("./code.png",'wb') as fp:
            fp.write(response.body) # response的二进制是body
        img = Image.open("./code.png")
        img = img.convert("L")
        code = pytesseract.image_to_string(img)
        # 登录接口
        login_url = "https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx"
        # 登录提交的表单数据
        data = {
            "__VIEWSTATE":	self.token1,
            "__VIEWSTATEGENERATOR":self.token2,
            "from":"http://so.gushiwen.org/user/collect.aspx",
            "email":"fanjianbo666@163.com",
            "pwd":"12345678",
            "code":code,
            "denglu":"登录"
        }
        # 返回出去一个post请求的下载器对象
        yield scrapy.FormRequest(url=login_url,formdata=data,callback=self.parse_login)

    # 定义一个回调函数,用于处理登录的响应数据
    def parse_login(self,response):
        print(response.text)
        pass

两个相互关联的爬虫

案例:爬取“穷游网”
“中国”的所有的旅游城市,要爬取的内容
1)城市名,去过的人数,常见的景点,城市的概况
2)进入每个城市的二级页面“旅行地”模块,提取出每个城市的旅行地的如下字段:地名,评分,评论数,推荐锦囊数,排名

city的爬虫器
# -*- coding: utf-8 -*-
import scrapy
from Qiongyou.items import QiongyouItem

class CitySpider(scrapy.Spider):
   name = 'city'
   allowed_domains = ['qyer.com']
   start_urls = ['https://place.qyer.com/china/citylist-0-0-%d/'%i for i in range(1,9)]

   def parse(self, response):
       # print(response.text)
       city_list = response.xpath("//ul[@class='plcCitylist']/li")
       for city in city_list:
           item = QiongyouItem()
           item["cityName"] = " ".join(city.xpath(".//h3//a//text()").extract())
           item["visitorNum"] = city.xpath(".//p[@class='beento']/text()").extract()[0]
           item["scenicSpot"] = "".join(city.xpath(".//p[@class='pois']//text()").extract())
           item["cityNum"] = city.xpath(".//h3//a/@href").extract()[0].split("/")[-2]
           # 取出城市的pid
           item["cityPid"] = city.xpath(".//p[@class='addPlanBtn']/@data-pid").extract()[0]
           # 城市的概况在下级页面中,所以在这里要匹配出下级页面的url
           next_url = "https://place.qyer.com/" + item["cityNum"] + "/profile/"
           print(next_url)
           # 发起请求,打开二级页面提取数据
           yield scrapy.Request(url=next_url,callback=self.parse_next,meta={"item":item})
           # response有一个属性叫做meta,用于记录响应的相关信息,这个属性可以自定义,在发起Request请求的时候,把我们item放入到meta,此时item就可以跟着响应数据对象传入到下级页面

   def parse_next(self,response):
       # print(response.meta)
       item = response.meta["item"] # 取出上级页面中传过来的item对象
       item["cityInfo"] = "\n".join(response.xpath("//div[@class='entry_main']//text()").extract()) # 继续解析上级页面中没有解析完的item

       yield item

#travel爬虫器
# -*- coding: utf-8 -*-
import scrapy
import redis
import json
class TravelSpider(scrapy.Spider):
   name = 'travel'
   allowed_domains = ['qyer.com']
   # start_urls = ['http://qyer.com/']
   def start_requests(self):
       print("开始请求...")
       # 1)从redis数据库中提取出城市pid和城市的代号
       rds = redis.StrictRedis(host="www.fanjianbo.com",port=6379,db=8)
       lens = rds.llen("Qiuyou:cityList")
       print(lens)
       city_list = rds.lrange("Qiuyou:cityList",0,lens)
       # print(city_list)
       # 定义两个列表分别用于存储pid和城市代号
       pid_list = []
       cityNum_list = []
       for c in city_list:
           city = json.loads(c)
           pid_list.append(city["cityPid"])
           cityNum_list.append(city["cityNum"])
       # 2)将城市代号拼接出城市的旅游景点的列表页,从中提取出总页数
       for i in range(len(cityNum_list)):
           city_url = "https://place.qyer.com/" + cityNum_list[i] + "/alltravel/"
           print("正在向:%s发起请求!"%city_url)
           yield scrapy.Request(url=city_url,callback=self.parse_city,meta={"pid":pid_list[i]})
   # 定义一个回调函数用于处理每个城市的旅游景点列表的页面
   def parse_city(self, response):
       pid = response.meta["pid"]
       # 解析出每个城市景点列表页的总页数
       total_pages = response.xpath("//a[@class='ui_page_item']/@data-page").extract()
       if len(total_pages) != 0:
           # 抓取每一页每一页的数据
           for page in range(1,int(total_pages[-1])+1):
               post_url = "https://place.qyer.com/poi.php?action=list_json"
               data = {
               'page': str(page),
               "type": "city",
               "pid": str(pid),
               "sort": '0',
               "subsort": "all",
               "isnominate": '-1',
               "haslastm": "false",
               "rank": '0'
               }
               yield scrapy.FormRequest(url=post_url,formdata=data,callback=self.parse_post)

   def parse_post(self, response):
       # print(response.text)
       # 练习:json解析并且存储景点页面
       pass

  • 管道文件
import redis
import json
class QiongyouPipeline(object):
    def open_spider(self,spider):
        # 判断爬虫
        if spider.name == "city":
            self.rds = redis.StrictRedis(host="www.fanjianbo.com",port=6379,db=8)
        pass
    def process_item(self, item, spider):
        if spider.name == "city":
            self.rds.lpush("Qiuyou:cityList",json.dumps(dict(item)))
        return item

    def close_spider(self,spider):
        pass

### Scrapy 中发送带参数的请求方法 在 Scrapy 中,可以通过多种方式实现带有参数的请求。以下是几种常见的方法及其适用场景: #### 方法一:通过 `scrapy.FormRequest` 提交 POST 请求 当需要向服务器提交表单数据时,可以使用 `scrapy.FormRequest` 来发送 POST 请求。这种方式适用于模拟登录或其他需要传递键值对形式的数据的情况。 ```python import scrapy class ExampleSpider(scrapy.Spider): name = 'example_spider' def start_requests(self): url = 'http://example.com/login' form_data = { "email": "your_email@example.com", "password": "your_password" } yield scrapy.FormRequest( url=url, formdata=form_data, callback=self.parse_page ) def parse_page(self, response): # 处理响应逻辑 pass ``` 这种方法会自动设置 Content-Type 为 `application/x-www-form-urlencoded` 并编码数据[^1]。 --- #### 方法二:通过 `meta` 参数附加 GET 请求参数 如果目标 URL 需要额外的查询参数,可以在发起请求时通过 `meta` 字段传递参数,并在回调函数中提取它们。 ```python import scrapy class ParamSpider(scrapy.Spider): name = 'param_spider' def start_requests(self): base_url = 'http://example.com/search' params = {'keyword': 'Scrapy', 'page': 1} yield scrapy.Request( url=base_url, meta={'params': params}, callback=self.parse ) def parse(self, response): params = response.meta.get('params') # 使用 params 变量进行后续操作 pass ``` 此方法允许灵活处理动态生成的参数组合[^2]。 --- #### 方法三:手动构建 URL 查询字符串 对于简单GET 请求,可以直接将参数拼接到 URL 后面作为查询字符串的一部分。 ```python from urllib.parse import urlencode url_base = 'https://buff.163.com/api/market/goods/price_history/buff' query_params = { 'game': 'csgo', 'goods_id': '35803', 'currency': 'CNY', 'days': '30', 'buff_price_type': '2', '_': '1681384999985' } full_url = f"{url_base}?{urlencode(query_params)}" yield scrapy.Request(full_url, callback=self.parse_prices) def parse_prices(self, response): # 解析价格历史数据 pass ``` 这种法适合于固定或少量变化的参数列表[^5]。 --- #### 方法四:自定义 `scrapy.Request` 的 Body Method 某些情况下,可能需要更精细地控制 HTTP 请求的内容格式(例如 JSON 数据)。此时可直接使用 `scrapy.Request` 并显式指定 `body` `method` 属性。 ```python import json import scrapy class JsonPostSpider(scrapy.Spider): name = 'json_post_spider' def start_requests(self): url = 'http://api.example.com/data' payload = {"key": "value"} headers = {'Content-Type': 'application/json'} yield scrapy.Request( url=url, body=json.dumps(payload), method="POST", headers=headers, callback=self.parse_response ) def parse_response(self, response): # 处理解码后的 JSON 响应 pass ``` 该方案特别适合 API 接口调用,尤其是那些接受 JSON 格式的负载的服务[^3]。 --- #### 总结 以上四种方法分别针对不同类型的请求需求提供了解决方案: - **`FormRequest`**: 主要用作表单提交工具; - **`meta` 参数附带**: 动态管理复杂上下文信息的理想选择; - **URL 拼接法**: 对简单 GET 请求最为便捷高效; - **自定义 Request**: 当涉及特殊 MIME 类型或者复杂的交互协议时尤为有用。 每种技术都有其特定的应用场合,在实际开发过程中可以根据具体业务逻辑选取最合适的手段来完成目标任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值