Scrapy 爬取旅游景点相关数据(六):代理使用

本期内容:(1)继续完善评论数据的爬取 (2) 代理的使用

1 创建数据库表

上期我们只打印了爬取到的数据,并没有入库,保存到数据,先执行以下SQL:

CREATE TABLE tb_comment (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
    tid VARCHAR(255) COMMENT '景点ID',
    username VARCHAR(255) COMMENT '评论的用户名',
    avatar VARCHAR(255) COMMENT '评论用户的头像 URL',
    comments TEXT COMMENT '评论的内容',
    label VARCHAR(20) COMMENT '情感分析分类',
    score decimal(10,2) comment '情感分析得分'
) COMMENT '评论数据表';

后续我们要做情感分析,所以预留了情感分析的字段。

2 编写管道

上一期已经把解析的代码写的差不多了,遗留了管道部分未写,下面补全:

# 保存mysql 景点评论
class TourCommentPipeline:
    def __init__(self, crawler):
        self.crawler = crawler
        # 连接 MySQL 数据库
        self.db = pymysql.connect(
            host=self.crawler.settings.get('DB_HOST'),
            user=self.crawler.settings.get('DB_USER'),
            password=self.crawler.settings.get('DB_PASS'),
            database=self.crawler.settings.get('DB_DATABASE'),
            charset=self.crawler.settings.get('DB_CHARSET')
        )
        self.cursor = self.db.cursor()
      
    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)
   
    def process_item(self, item, spider):
        # 检查数据是否已存在
        sql = "SELECT COUNT(*) FROM tb_comment WHERE tid = %s and username= %s "
        self.cursor.execute(sql, (item["tid"],  item['username']))
        count = self.cursor.fetchone()[0]
        if count > 0:
            spider.log(f"Data already exists: {item['tid'], item['username']}")
            return item

        # 插入新数据
        sql = ("INSERT INTO tb_comment (tid, username, avatar, comments) "
               "VALUES (%s, %s, %s, %s)")
        values = (
            item["tid"],
            item["username"],
            item["avatar"],
            item["comments"],
        )
        try:
            self.cursor.execute(sql, values)
            self.db.commit()
            self.total_items += 1
            spider.log(f"Saved data: {item['username']}")
        except pymysql.Error as e:
            self.db.rollback()
            spider.log(f"Error saving data: {item['username']} - {e}")
        return item

    def close_spider(self, spider):
        self.cursor.close()
        self.db.close()

3 测试结果

测试爬取的结果是不太给力的,基本上爬取没多少时间,就会报ConnectionRefusedError 的异常,原因应该是目标网站已经监测到我们的爬取行为了。

中间尝试了调低scrapy的并发量和增加每次下载的延时,在settings.py里

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 2  #并发2,甚至我试过1,然并卵
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 2  # 这个调低了,爬取速度巨慢好吗?

修改这个参数会降低爬取效率,而且并不一定能绕开请求拒绝的问题(再说如果爬取非常慢还有啥意义呢 😭 )

4 代理 😎

为了改变这个局面,在爬虫中需要加入代理机制,本期的话先给出提取代理服务器的代码并且做一个简单的访问测试。

首先需要一个代理的来源,这里找了一家服务商(具体名字不提供了),提取的代码如下:

def get_proxy(key, num):
    response = requests.get(f'https://******/get?key={key}&num={num}')
    if response.status_code == 200:
        proxies = []
        ip_pool = []
        proxy_data = response.json()
        # 假设返回的JSON数据中包含代理IP地址
        # 例如: {"proxy": "http://123.45.67.89:8080"}
        for p in proxy_data['data']:
            # print(p)
            proxies.append(p['server'])   #要用的是这个地址
            ip_pool.append(p['proxy_ip'])
        print('ip_pool:', ip_pool)
        return proxies
    else:
        return []

返回的是一个代理服务器的列表,例如: [ 123.45.67.89:8080]

然后怎么测试这个呢? 可以写如下demo代码:

 
# 测试通过代理访问网站
import requests
def test_proxy_request():
    ip = "http://123.45.67.89:8080"
    # 代理设置
    proxy = {
        'http': 'http://代理服务商可能提供的KEY,密码之类的前缀' + ip,
    }

    # 要访问的目标 URL
    url = 'https://place.qyer.com/poi/V2UJYlFiBzRTZVI7Cmk/review/'

    try:
        # 通过代理发送请求
        response = requests.get(url, proxies=proxy, timeout=10)

        # 检查返回状态码
        if response.status_code == 200:
            print("访问成功,返回状态码为200")
        else:
            print(f"访问失败,返回状态码为{response.status_code}")
    except requests.exceptions.RequestException as e:
        print(f"请求出错: {e}")

# 运行测试
test_proxy_request()

那在scrapy中怎么使用代理,也是非常简单,只需要修改precess_request方法:

    def process_request(self, request, spider):
        if self.proxies == []:
            self.update_proxies()
        proxy = random.choice(self.proxies)
        # print(f"目前使用的代理是:http://{proxy}")
        request.meta['proxy'] = f"http://{self.user}:{self.passw}@{proxy}"  # 这个是我使用的代理的拼写方法,不同的服务商可能不同,这行需要修改!

更新代理池的方法,这里每次更新16个代理地址,可以根据实际情况调整:

    def update_proxies(self):
        self.proxies = get_proxy(self.user, 16)

5 小结

本期通过设置代理实现了对评论数据的爬取和入库,不过实际使用过程中,代理池是需要更新的,还有很多异常情况需要处理,需要优化的细节很多,请关注本专栏,麦麦会在后续的博文中给大家带来。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦麦大数据

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值