python---爬虫[1]:页面分析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u012319493/article/details/86929921

页面分析及数据抓取

anaconda + scrapy 安装:https://blog.csdn.net/dream_dt/article/details/80187916
用 scrapy 初始化一个爬虫:https://blog.csdn.net/dream_dt/article/details/80188592

要爬的网页:
在这里插入图片描述

复制网址后,在 Anaconda Prompt 中,cd 到项目所在目录,输入:

scrapy genspider skirt https://item.taobao.com/item.htm?id=537194970660&ali_refid=a3_430673_1006:1105679232:N:%E5%A5%B3%E8%A3%85:30942d37a432dd6b95fad6c34caf5bd5&ali_trackid=1_30942d37a432dd6b95fad6c34caf5bd5&spm=a2e15.8261149.07626516002.3

会生成一个新的文件:
在这里插入图片描述

skirt.py

# -*- coding: utf-8 -*-
import scrapy


class SkirtSpider(scrapy.Spider):
    name = 'skirt'
    allowed_domains = ['https://item.taobao.com']  # 只保留域名
    start_urls = ['http://https://item.taobao.com/item.htm?id=537194970660/']  # 主页面

    def parse(self, response):
        pass

创建一个 main 函数:
在这里插入图片描述

main.py

# -*- coding: utf-8 -*-

from scrapy.cmdline import execute

import sys
import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))  # 导入执行路径

execute(["scrapy", "crawl", "skirt"])  # 在 shell 中执行命令

修改 settings.py,否则会把所有不符合规则的页面过滤掉

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

获取单价

在 Anaconda Prompt 中输入

scrapy shell https://item.taobao.com/item.htm?id=537194970660&ali_refid=a3_430673_1006:1105679232:N:%E5%A5%B3%E8%A3%85:30942d37a432dd6b95fad6c34caf5bd5&ali_trackid=1_30942d37a432dd6b95fad6c34caf5bd5&spm=a2e15.8261149.07626516002.3

在这里插入图片描述
因为 tb-rmb-num 只有一个,可以用 class 选择器定位,在 Anaconda Prompt 中输入

response.css('.tb-rmb-num')

在这里插入图片描述

为了拿到 128 那个值,输入

response.css('.tb-rmb-num::text')

在这里插入图片描述

response.css('.tb-rmb-num::text').extract()

在这里插入图片描述

response.css('.tb-rmb-num::text').extract()[0]

在这里插入图片描述
修改 skirt.py

def parse(self, response):
        
        # 获取单价
        price = response.css('.tb-rmb-num::text').extract()[0]

获取评论数

在这里插入图片描述
在 Anaconda Prompt 中输入

response.css('#J_RateCounter::text').extract()

在这里插入图片描述
没有拿到数据,说明该数据可能是通过 js 动态渲染的,需要分析源代码。
在这里插入图片描述
将 rateCountterApi 对应的 url 复制到浏览器中,得到如下结果
在这里插入图片描述
可见该评论数位于第一条 script 中的 rateCounterApi 字段。
在 Anaconda Prompt 中输入

response.css('script::text')[0].extract()

在这里插入图片描述
修改 skirt.py

def parse(self, response):
        
        # 获取单价
        price = response.css('.tb-rmb-num::text').extract()
        
        # 获取页面渲染脚本的第一个结构
        first_js_script = response.css('script::text')[0].extract() 

筛选数据,获取评论数

第一条 js 数据中第一个字段的开头
在这里插入图片描述
第一条 js 数据中第一个字段的结尾
在这里插入图片描述

用正则表达式匹配出第一条 js 数据中第一个字段。
\s:空白符
\S:非空白符
*:重复任意多次

匹配出的结果是一个 list,skirt.py 中添加

import re
g_config = re.findall('var g_config = ([\s\S]*)g_config.tadInfo', first_js_script)[0]

需要匹配出 rateCounterApi 对应的 url
在这里插入图片描述

skirt.py 中添加

rate_counter_api = re.findall("rateCounterApi   : '//(.*)',", g_config)[0]

访问获取评论的 url,skirt.py 中添加,

import requests
rate_count_response = resquests.get("http://" + rate_counter_api)  # null({"count":627})

得到评论数量,skirt.py 中添加,

rate_count = re.findall('"count":(.*)}', rate_count_response)[0]

现在,skirt.py 成为:

# -*- coding: utf-8 -*-
import scrapy
import re
import requests

class SkirtSpider(scrapy.Spider):
    name = 'skirt'
    allowed_domains = ['https://item.taobao.com']  # 只保留域名
    start_urls = ['https://item.taobao.com/item.htm?id=537194970660&ali_refid=a3_430673_1006:1105679232:N:%E5%A5%B3%E8%A3%85:30942d37a432dd6b95fad6c34caf5bd5&ali_trackid=1_30942d37a432dd6b95fad6c34caf5bd5&spm=a2e15.8261149.07626516002.3']
    
    def parse(self, response):
        
        # 获取单价
        price = response.css('.tb-rmb-num::text').extract()
        
        ''' 获取评论数量 '''
        
        # 获取页面渲染脚本的第一个结构
        first_js_script = response.css('script::text')[0].extract()[0]
        
        g_config = re.findall('var g_config = ([\s\S]*)g_config.tadInfo', first_js_script)[0]
        
        rate_counter_api = re.findall("rateCounterApi   : '//(.*)',", g_config)[0]
        
        # 访问获取评论的 url
        rate_count_response = requests.get("http://" + rate_counter_api)  # null({"count":627})

        # 获取评论数量
        rate_count = re.findall('"count":(.*)}', rate_count_response.text)[0]
    
        print(price)
        print(rate_count)

不知为什么,运行 mian 函数后会出现错误:

 raise error.ReactorNotRestartable()
	ReactorNotRestartable

于是在 Anaconda Prompt 中输入:

scrapy crawl skirt

在这里插入图片描述
得到结果:
在这里插入图片描述

获取具体的评论信息

在这里插入图片描述
同样不能从页面直接获取,是通过 js 脚本从别的地方加载进来的,与评论数量的获取方式类似。

选择“Network”选项,清空一下
在这里插入图片描述

点击评论第 2 页,可以看到一些结果

在这里插入图片描述

点击那个链接,验证是否为评论信息
在这里插入图片描述
该如何获取该评论信息?切换到“Headers”选项,可以看到 Request URL
在这里插入图片描述
将该 url 复制后,复制到新的浏览器查询页面后,可以得到:
在这里插入图片描述
所以接下来分析该 url,里面有哪些东西是可用的。该 url 具体如下

https://rate.taobao.com/feedRateList.htm?auctionNumId=537194970660&userNumId=794196473&currentPageNum=2&pageSize=20&rateType=&orderType=sort_weight&attribute=&sku=&hasSku=false&folded=0&ua=098%23E1hvKpvWvPvvUvCkvvvvvjiPR2MhAjnCPLd9zjrCPmP9gjDnRFsy6jEmn2MUsjrm9phvVZ2MWlAQ7rMNz1CKz8otUSiswIFU1qYbJzWPvpvhvv2MMQyCvhQhhQyvCsxleExrV8t%2Bm7zhaf9gKFnfIExrs8TZfvDrAjc6%2Bul1bbmxfwp4d56Ofw3l%2Bb8rwkM6D7zhVut%2Bm7zh6j7J%2B3%2BiafmxfBeKKphv8vvvvvCvpvvvvvv2vhCvmnGvvvWvphvW9pvvvQCvpvs9vvv2vhCv2RmivpvUvvmv%2BQeoltAEvpvVmvvC9jXmvphvC9vhvvCvp2yCvvpvvvvviQhvCvvv9U8jvpvhvvpvv2yCvvpvvvvvdphvmQ9ZW9UYPpLY5gyA&_ksTS=1543128829263_1021&callback=jsonp_tbcrate_reviews_list

可以看到用 & 符号连接一些参数。以下这部分 url 比较好懂,而后面的部分不好懂,先忽略,用以下新的 url 打开新的页面

https://rate.taobao.com/feedRateList.htm?auctionNumId=537194970660&userNumId=794196473&currentPageNum=2&pageSize=20

在这里插入图片描述
可以看到请求成功,说明 url 后面的部分没有用。

同理,userNumId 参数没有用,可删掉,将 currentPageNum = 1,可得到如下页面

https://rate.taobao.com/feedRateList.htm?auctionNumId=537194970660&currentPageNum=1&pageSize=20

在这里插入图片描述
而参数 pageSize 表示一次请求多少条评论信息,默认是 20 条。

接下通过拼接的方式得到以下类似的 url,以获取具体评论信息。

https://rate.taobao.com/feedRateList.htm?auctionNumId=537194970660&currentPageNum=2&pageSize=20

获得拼接 url 的前面部分,即 “https://rate.taobao.com/feedRateList.htm”
在这里插入图片描述

在 Anaconda Prompt 中输入

response.css('#reviews')

在这里插入图片描述
然后从中获取 url,“::” 后面跟 attr,而不是 text

data_listapi_url = response.css('#reviews::attr(data-listapi)').extract()[0]

在这里插入图片描述

# 评论的 url
feed_rate_list_url = re.findall("\/\/(.*?)\?", data_listapi_url)[0]

\:转义字符
?:遇到第一个匹配的后停止
在这里插入图片描述
获取需要拼接的 url 中的参数:宝贝 id

# 宝贝 id
auction_num_id = re.findall("auctionNumId=(.*?)&", data_listapi_url)[0]

在这里插入图片描述

获取所有评论信息

接下来完成每页 url 的拼接。

# 计算一共有多少页的评论
page_size = 20
pages = math.ceil(int(rate_count) / page_size)  # rate_count 为前面获取的评论数量

拼接各种参数,得到 url

for current_page_number in range(1, pages):
	yield scrapy.Request(url = "http://"+ feed_rate_list_url 
			+ "?auctionNumId=" + auction_num_id
			+ "&currentPageNum=" + str(current_page_number)
			+ "&pageSize=" + str(page_size),
		         callback = self.parse_rate_list)  # 如何处理该页面

回调函数

def parse_rate_list(self, response):
	print(response.text)

现在,skirt.py 如下

# -*- coding: utf-8 -*-
import scrapy
import re
import requests
import math

class SkirtSpider(scrapy.Spider):
    name = 'skirt'
    
    # 允许的域名,如果没有把域名写在这里,那么将会过滤掉
    allowed_domains = ['item.taobao.com',
                       'rate.taobao.com']  # 只保留域名
    # 从哪个页面开始抓取
    start_urls = ['https://item.taobao.com/item.htm?id=537194970660&ali_refid=a3_430673_1006:1105679232:N:%E5%A5%B3%E8%A3%85:30942d37a432dd6b95fad6c34caf5bd5&ali_trackid=1_30942d37a432dd6b95fad6c34caf5bd5&spm=a2e15.8261149.07626516002.3']
    
    def parse(self, response):
        
        # 连衣裙的单价
        price = response.css('.tb-rmb-num::text').extract()[0]
        
        ''' 获取评论数量 '''
        
        # 获取到页面渲染的第一个脚本的数据结构
        first_js_script = response.css('script::text')[0].extract()  
        
        # 正则匹配到g_config字段
        g_config = re.findall('var g_config = ([\s\S]*)g_config.tadInfo', first_js_script)[0]
        
        # 正则匹配,拿到页面的评论 url
        rate_counter_api = re.findall("rateCounterApi   : '//(.*)',", g_config)[0]
        
        # 访问获取评论的 url
        rate_count_response = requests.get("http://" + rate_counter_api)  # null({"count":627})

        # 获取评论数量
        rate_count = re.findall('"count":(.*)}', rate_count_response.text)[0]
    
        # 该请求可获取具体的评论信息
        # https://rate.taobao.com/feedRateList.htm?auctionNumId=537194970660&currentPageNum=2&pageSize=20
        
        # 拿到 data_listapi_url,这个能够匹配到域名
        data_listapi_url = response.css('#reviews::attr(data-listapi)').extract()[0]
    
        # 获取到评论的 url
        feed_rate_list_url = re.findall("//(.*?)\?", data_listapi_url)[0]
        
        # 宝贝 id
        auction_num_id = re.findall("auctionNumId=(.*?)&", data_listapi_url)[0]

        # 设置一个值,一页获取的评论数量
        page_size = 20
        
        # 计算一共有多少页的评论
        pages = math.ceil(int(rate_count) / page_size)

        # 迭代一共有多少页,然后分别请求每一页评论
        for current_page_number in range(1, pages):
            yield scrapy.Request(url = "http://"+ feed_rate_list_url 
                                 + "?auctionNumId=" + auction_num_id
                                 + "&currentPageNum=" + str(current_page_number)
                                 + "&pageSize=" + str(page_size),
                                 callback = self.parse_rate_list)  # 如何处理该页面

    # 解析具体的评论
    def parse_rate_list(self, response):
        print(response.text) 

运行

scrapy crawl skirt

在这里插入图片描述
结果如下
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u012319493/article/details/86929921
今日推荐