返回介绍

14.2 爬取链家经纪人成交数据

发布于 2025-04-21 19:15:31 字数 5908 浏览 0 评论 0 收藏

14.2.1 链家移动页面分析

爬取链家经纪人成交数据及应对反爬虫的设置

这里用一个实例来演示如何把爬取到的数据存储到 MongoDB 服务器。这次实战的目标是链家网站经纪人成交数据。爬取这个数据还是很有意义的,可以帮助我们判断经纪人的成交能力。为了简单,这次爬取链家网的移动页面。打开链家移动页面,如图 14-5 所示。

图 14-5 链家移动页面

单击页面中间位置的“找经纪人”这个栏目,进入链家北京的经纪人列表页,如图 14-6 所示。

图 14-6 链家北京的经纪人列表页

很容易发现这是一个动态页面,向下拉滚动条,会不断有新的数据出来。通过使用 Chrome 浏览器的“检查”功能,可以很快判断出其翻页实际上是请求了如下形式的 URL。

https://m.lianjia.com/bj/jingjiren/?page_size=15&_t=1&offset=15 

最后的 offset 值随着滚动翻页每次增加 15。知道了这个规律,就可以使用一个列表推导式生成所有需要爬取的经纪人列表页的 URL。

通过经纪人列表页能爬取到经纪人详情页的 URL。打开经纪人详情页见图 14-7,其 URL 类似如下形式。

图 14-7 经纪人详情页

https://m.lianjia.com/bj/jingjiren/1000000010140377/ 

在经纪人详情页中单击“查看全部成交记录”,进入经纪人的成交记录页面,其 URL 类似如下形式。

https://m.lianjia.com/bj/jingjiren/chengjiao/1000000010140377/ 

对比一下经纪人详情页面 URL 和其成交记录页面的 URL,可以发现成交记录页 URL 的构造规律,其实就是 URL 中间增加了 chengjiao/而已。

下面再看一下经纪人成交记录页面是如何翻页的,图 14-8 所示为经纪人成交记录页面。

图 14-8 经纪人成交记录页面

通过分析会发现,成交记录页也是一个动态页面,其翻页类似经纪人列表页,实际请求了类似下面形式的 URL。

https://m.lianjia.com/bj/jingjiren/chengjiao/
1000000010140377/?page_size=20&_t=1&offset=20 

随着向下翻页,URL 的 offset 值每页增加 20。因此爬虫要实现翻页,只需要改变 offset 的值即可。可以使用两种方式来实现翻页。

(1)因为经纪人详情页已经给出了经纪人的成交套数,可以根据成交套数,用列表推导式来生成所有的翻页 URL。例如上面那位经纪人成交套数为 N,则他的成交记录页 URL 可以按如下方式生成。

#先定义 URL 前面部分
pre_url = ('https://m.lianjia.com/bj/jingjiren/chengjiao/' 
'1000000010140377/?page_size=20&_t=1&offset=') 
deal_url = [pre_url + str(i*20) for i in range(N//20+1)] 

这种处理方式实质上是把成交记录页面总数计算出来并生成所有成交记录页面 URL,然后再请求,特别适合使用 Requests 编写爬虫时使用。

(2)在详情页解析函数中回调它本身,然后判断 response 是否有内容,有的话说明还有成交记录,那就继续请求下一页并继续使用详情页解析函数作为回调函数。这种方式更适合 Scrapy。下面将使用这种方式实现翻页。

14.2.2 定义 Items、编写 spider

第一步,设置一个 pachong5 的项目,并使用 BasicSpider 模板生成 spider。然后定义 Items,主要包括经纪人姓名、负责板块、成交小区、成交时间、成交总价这 5 项内容,打开 items.py 进行设置。

import scrapy
 
class Pachong5Item(scrapy.Item): 
    name = scrapy.Field() 
    region = scrapy.Field() 
    apartment = scrapy.Field() 
    time = scrapy.Field() 
total_price = scrapy.Field() 

第二步,按照对网站页面的分析,编写 spider。现在假设要爬取 10000 个经纪人的成交数据,用列表推导式生成 start_urls。当然也可以使用生成器,因为 start_urls 中的 URL 只会请求一次。

import scrapy
from pachong5.items import Pachong5Item 
 
class LianjiaSpider(scrapy.Spider): 
    name = 'lianjia' 
    allowed_domains = ['m.lianjia.com'] 
    #生成列表页 URL 
    start_urls = ( 
         'https://m.lianjia.com/bj/jingjiren?page_size=15&t=1&offset=' 
         + str(x) for x in range(0,10000,15) 
) 

然后定义经纪人列表页解析函数。思路是:从经纪人列表页中提取经纪人姓名、负责板块及经纪人详情页 URL,使用这个 URL 构造经纪人成交记录页的 URL,再对构造的经纪人成交记录页 URL 发起请求。

def parse(self, response):
    #获取每个经纪人的代码段 
    agentlist = response.xpath( 
"//*[@class='lists q_agentlist']/li[@class='pictext flexbox box_center_v']" 
)  
    for agent in agentlist: 
        item = Pachong5Item() 
        item['name'] = agent.xpath( 
'div[2]/div[1]/span[1]/a/text()').extract_first() 
        item['region'] = agent.xpath( 
'div[2]/div[2]/span[1]/text()').extract_first() 
        #构造经纪人成交记录页第一页的 URL 
        deal_url = 'https://m.lianjia.com/bj/jingjiren/chengjiao/' 
+ jjr.xpath('div[2]/div[1]/span[1]/a/@href' 
).extract_first().split('/')[-2] 
+ '?page_size=20&_t=1&offset=0'  
        yield scrapy.Request(url=deal_url, meta={'item':item},  
callback=self.parse_deal) 

在构造经纪人成交页网址 deal_url 时,网址最后面增加了“?page_size=20&_t=1&offset=0”这样一段,这并非画蛇添足,主要是希望在下面的 parse_deal 函数中可以得到统一的 URL 格式,从而方便地构造出成交页的下一页的网址。这里还使用了 meta 这个 Request 参数来传递已经提取到的 Item 数据到 parse_deal 函数。

第三步,定义 parse_deal 方法。

    def parse_deal(self, response):
        chengjiaos = response.xpath( 
                     "//*[@class='mod_cont']/ul/li[@class='pictext']") 
        if deal:         #判断是否还有成交记录 
            item = response.meta['item'] 
#构造成交记录下一页的 URL,在当前页 offset 值的基础#上增加 20 
            next_url = response.url.rsplit('=',1)[0]+'=' 
                       + str(int(response.url.rsplit('=',1)[1])+20) 
#请求成交记录下一页 
#注意要使用 meta 参数继续传递已抓取的 item 数据 
yield scrapy.Request(url=next_url, meta={'item':item},  
                     callback=self.parse_deal) 
for deal in deals: 
    item['apartment'] = deal.xpath('a/div[2]/div[1]/text()').extract_first() 
    item['time'] = deal.xpath('a/div[2]/div[3]/text()').extract_first() 
    item['total_price'] = deal.xpath('a/div[2]/div[4]/span[1]/em/text()
').extract_first() 
yield item 

这里使用了上面介绍的第二种翻页方式。首先判断 response 中是否有成交列表数据,如果有,就先构造成交记录下一页的 URL,也就是把当前请求页面的 URL 从 offset 后面的‘ = ’那里分开,将当前页的 offset 值加上 20 构造为下一页网址 next_url,然后使用 scrapy.Request 请求并设置回调函数为 parse_deal 函数本身,另外,scrapy.Request 还需要将上面列表页抓取到的 Item 数据继续传递下去。最后,解析出当前成交记录页的数据并返回 Item。

第四步,设置 settings。为了防止被链家网反爬虫禁止,在 settings 中设置如下参数。

     ROBOTSTXT_OBEY = False
     COOKIES_ENABLED = False 
     DOWNLOAD_DELAY = 5 
     USER_AGENT='Mozilla/5.0 (Windows NT 6.1; Win64; x64) \ 
                AppleWebKit/537.36 (KHTML, like Gecko) \ 
                Chrome/63.0.3239.132 Safari/537.36'

至此,爬虫部分编写完毕,读者可以在命令行中运行一下,查看是否能正确地爬取到数据。运行结果如图 14-9 所示。从图中可以看到,爬虫能够正确地爬取到数据。

图 14-9 链家经纪人成交数据爬虫运行日志

本节定义了链家经纪人成交数据爬虫的 Items 和 spider。由于链家网的 Web 页面无法直接查看成交数据,这里爬取了链家网的移动页面。我们知道,爬取返回的 Item 交给了 pipeline 处理,因此下一节我们将讲解在 pipeline 中如何设置存储数据到 MongoDB。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。