jose@huang 2024-03-28 13:04 采纳率: 66.7%
浏览 7

scrapy的全站爬虫,其代理ip池,如何设置?

0.问题背景:全站爬虫crawlSpider,如何添加爬虫代理池?
1.代码

# spider文件: sun.py
import scrapy
from time import sleep
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from faker import Faker
import requests
from lxml import etree
from ..items import Main00CrawlproItem


class SunSpider(CrawlSpider):
    fake = Faker()
    headers = {
        'User-Agent': fake.user_agent()
    }

    def __init__(self):
        super().__init__()
        self.process_proxy_pool()
    name = "sun"
    # allowed_domains = ["www.xxx.com"]
    start_urls = ["https://wz.sun0769.com/political/index/politicsNewest"]

    # link就表示创建出来的一个链接提取器
    # allow参数后面要跟一个正则表达式,就可以作为链接提取的规则
    # link首先会去start_urls表示的页面中进行链接的提取
    link_title = LinkExtractor(allow=r'id=1&page=(\d+)')  # 爬取标题的link
    link_detailPageUrl = LinkExtractor(allow=r'/political/politics/index?id=(\d+)')  # 爬取详情页的link

    # 创建了一个规则解析器
    # 链接提取器LinkExtractor提取到的链接会发送给Rule这个规则解析器
    # 规则解析器接收到链接后,会对链接进行请求发送,并且根据callback指定的函数进行数据解析
    # 如果callback 为None,follow 默认设置为 True;添加回调函数callback后,为 False,不跟踪
    rules = (
        # 启用ip_pool之前,follow设置为False,否则被反爬
        Rule(link_title, callback="parse_item", follow=True),
        Rule(link_detailPageUrl, callback='parse_detail')
    )

    # 解析方法的调用次数取决于link提取到的链接的个数 - 此处response为每一个页面,即第X页的数据
    def parse_item(self, response):
        # item = {}
        li_list = response.xpath('//ul[@class="title-state-ul"]/li')
        for li in li_list:
            title = li.xpath('./span[@class="state3"]/a/text()').extract_first()
            print(title)
        sleep(1)
        #item["domain_id"] = response.xpath('//input[@id="sid"]/@value').get()
        #item["name"] = response.xpath('//div[@id="name"]').get()
        #item["description"] = response.xpath('//div[@id="description"]').get()
        # return item

    def parse_detail(self, response):
        detail_content = response.xpath('//div[@class="details-box"]/pre/text()').extract_first()
        print(detail_content)

    def check_proxy(self, proxy, url='http://httpbin.org/get'):  # # this def is what I added.;检测ip是否可用
        proxies = {
            'http': 'http://' + proxy,
            'https': 'http://' + proxy,
        }
        try:
            response = requests.get(url=url, proxies=proxies, headers=self.headers, timeout=5)
            if response.status_code == 200:
                return True
            else:
                return False
        except:
            False

    def process_proxy_pool(self):  # this def is what I added.  # 通过API获取ip
        # for cookie
        sess = requests.Session()
        url_getapi = 'https://jahttp.zhimaruanjian.com/getapi/'
        sess.get(url=url_getapi, headers=self.headers)

        # 构建一个Proxy pool
        proxy_pool = []
        # API url
        proxy_url = 'http://webapi.http.zhimacangku.com/getip?neek=321a408a&num=3&type=1&time=4&pro=0&city=0&yys=0&port=11&pack=0&ts=0&ys=0&cs=0&lb=1&sb=&pb=4&mr=1&regions='

        response = sess.get(url=proxy_url, headers=self.headers)
        print(f'{response} in class.')
        response.encoding = 'utf8'
        response_text = response.text
        tree = etree.HTML(response_text)
        ip_list = tree.xpath('/html/body//text()')
        print(f'len(ip_list): {len(ip_list)} \nip: {ip_list}')
        all_ips = ip_list[0].split('\r\n')[
                  :-1]  # ['113.237.5.78:4256', '123.245.248.58:4231', '218.86.19.32:4215', '']
        print(all_ips)
        for ip in all_ips:
            if self.check_proxy(ip):
                proxy_pool.append(ip)
        item = Main00CrawlproItem()
        item['ip_list'] = all_ips
        yield item
        print(proxy_pool)
        # return proxy_pool
##################################################
# item文件: items.py
import scrapy

class Main00CrawlproItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    ip_list = scrapy.Field()

2.个人初步思路:在爬虫文件(spider.py),写了获取代理IP池的函数,ip池是一个list,想要然后封装给item对象。
目前问题:0.爬虫文件(spider.py)的ip代理池函数该如何触发运行?
1.想通过中间键的下载中间键(Main00CrawlproDownloaderMiddleware)的def process_request(self, request, spider)来获取代理ip(池),以达到设置代理的目的。想把item对象(即代理ip池)通过request.meta传给中间键,怎么传?
PS:或者另有其它什么方法来添加代理ip池
3.操作环境: windows 11, py 3.10, pycharm

  • 写回答

1条回答 默认 最新

  • 阿里嘎多学长 2024-03-28 13:17
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    在Scrapy中,使用代理IP池通常涉及到以下几个步骤:

    1. 获取代理IP:你已经在process_proxy_pool方法中实现了获取代理IP的功能。
    2. 封装代理IP到请求元数据:你需要在每个请求中添加代理IP信息。这可以通过在start_requests方法中修改请求对象来实现。
    3. 使用下载中间件处理代理:你需要创建一个下载中间件,该中间件在发送请求前检查并设置代理。

    以下是针对你现有代码的修改建议:

    1. 修改start_requests方法

    SunSpider类中,添加start_requests方法来设置请求的代理:

    def start_requests(self):
        for url in self.start_urls:
            # 获取代理IP
            proxy = self.process_proxy_pool()
            # 将第一个可用的代理IP设置到请求的meta中
            yield scrapy.Request(url=url, callback=self.parse_item, meta={'proxy': proxy[0]})
    

    注意:这里我假设process_proxy_pool返回的是一个包含可用代理的列表。如果需要随机选择代理,可以使用random.choice()

    2. 创建下载中间件

    settings.py中,启用新的下载中间件:

    DOWNLOADER_MIDDLEWARES = {
        'myproject.middlewares.ProxyMiddleware': 610,  # 选择一个合适的顺序值
    }
    

    然后创建middlewares.py文件(如果还没有的话),并添加ProxyMiddleware

    class ProxyMiddleware:
        def process_request(self, request, spider):
            # 从请求的meta中获取代理
            proxy = request.meta.get('proxy')
            if proxy:
                # 设置代理到请求头
                request.meta['proxy'] = f'http//{proxy}'
    

    这样,每个请求都会带有从start_requests传递的代理IP,下载中间件会将这个代理设置到请求头中。

    注意事项

    • 确保你的代理服务提供稳定、有效的IP,否则可能会影响爬虫的稳定性。
    • 为了提高效率和避免被封,你可能需要在每次请求之间切换不同的代理。
    • 你可能还需要处理请求失败的情况,例如当代理不可用时,可以尝试下一个代理或重试请求。
    评论

报告相同问题?

问题事件

  • 创建了问题 3月28日

悬赏问题

  • ¥15 oracle数据库备份、
  • ¥15 关于Finetune模型,CUDA error: device-side assert triggered 报错
  • ¥15 能将阿里云上多个设备的信息能上传给小程序吗
  • ¥50 QT6.7 Camera预览窗口,camera分辨率设置
  • ¥15 车机是安卓4.4.3,车机没有gps,我想用外置蓝牙gps。所以在用安卓模拟位置服务时候,我下载的相关软件不显示在列表里
  • ¥15 matlab水位控制系统(详解)
  • ¥15 CST软件仿真,已知中心线方程构建图形
  • ¥15 supLink 用户定位
  • ¥15 odoo17生产成品入出库会计日记账设置及自动产生会计分录
  • ¥15 MCU控制20V PWM波输出的控制电路