2021年6月30日星期三

数据采集实战(一)-

概述

最近在学习python的各种数据分析库,为了尝试各种库中各种分析算法的效果,陆陆续续爬取了一些真实的数据来。

顺便也练习练习爬虫,踩了不少坑,后续将采集的经验逐步分享出来,希望能给后来者一些参考,也希望能够得到先驱者的指点!

采集工具

其实基本没用过什么现成的采集工具,都是自己通过编写代码来采集,虽然耗费一些时间,但是感觉灵活度高,可控性强,遇到问题时解决的方法也多。

一般根据网站的情况,如果提供API最好,直接写代码通过访问API来采集数据。
如果没有API,就通过解析页面(html)来获取数据。

本次采集的数据是链家网上的成交数据,因为是学习用,所以不会去大规模的采集,只采集了南京各个区的成交数据。

采集使用puppeteer库,Puppeteer 是一个 Node 库,它提供了高级的 API 并通过 DevTools 协议来控制 Chrome(或Chromium)。
通俗来说就是一个 headless chrome 浏览器: https://github.com/puppeteer/puppeteer

通过 puppeteer,可以模拟网页的手工操作方式,也就是说,理论上,能通过浏览器正常访问看到的内容就能采集到。

采集过程

其实数据采集的代码并不复杂,时间主要花在页面的分析上了。

链家网的成交数据不用登录也可以访问,这样就省了很多的事情。
只要找出南京市各个区的成交数据页面的URL,然后访问就行。

页面分析

下面以栖霞区的成交页面为例,分析我们可能需要的数据。

页面URL: https://nj.lianjia.com/chengjiao/qixia/
image.png
根据页面,可以看出重复的主要是红框内的数据,其中销售人员的姓名涉及隐私,我们不去采集。
采集的数据分类为:(有的户型可能没有下面列的那么全,缺少房屋优势字段,甚至成交价格字段等等)

  1. name: 小区名称和房屋概要,比如:新城香悦澜山 3室2厅 87.56平米
  2. houseInfo: 房屋朝向和装修情况,比如:南 北 | 精装
  3. dealDate: 成交日期,比如:2021.06.14
  4. totalPrice: 成交价格(单位: 万元),比如:338万
  5. positionInfo: 楼层等信息,比如:中楼层(共5层) 2002年建塔楼
  6. unitPrice: 成交单价,比如:38603元/平
  7. advantage: 房屋优势,比如:房屋满五年
  8. listPrice: 挂牌价格,比如:挂牌341万
  9. dealCycleDays: 成交周期,比如:成交周期44天

核心代码

链家网上采集房产成交数据很简单,我在采集过程中遇到的唯一的限制就是根据检索条件,只返回100页的数据,每页30条。
也就是说,不管什么检索条件,链家网只返回前3000条数据。
可能这也是链家网控制服务器访问压力的一个方式,毕竟如果是正常用户访问的话,一般也不会看3000条那么多,返回100页数据绰绰有余。

为了获取想要的数据,只能自己设计下检索条件,保证每个检索条件下的数据不超过3000条,最后自己合并左右的采集结果,去除重复数据。

这里,只演示如何采集数据,具体检索条件的设计,有兴趣根据自己需要的数据尝试下即可,没有统一的方法。

通过puppeteer采集数据,主要步骤很简单:

  1. 启动浏览器,打开页面
  2. 解析当前页面,获取需要的数据(也就是上面列出的9个字段的数据)
  3. 进入下一页
  4. 如果是最后一页,则退出程序
  5. 如果不是最后一页,进入步骤2

初始化并启动页面

import puppeteer from "puppeteer";(async () => { // 启动页面,得到页面对象 const page = await startPage();})();// 初始化浏览器const initBrowser = async () => { const browser = await puppeteer.launch({ args: ["--no-sandbox", "--start-maximized"], headless: false, userDataDir: "./user_data", ignoreDefaultArgs: ["--enable-automation"], executablePath:  "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", }); return browser;};// 启动页面const startPage = async (browser) => { const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); return page;};

采集数据

import puppeteer from "puppeteer";(async () => { // 启动页面,得到页面对象 const page = await startPage(); // 采集数据 await nanJin(page);})();const mapAreaPageSize = [ // { url: "https://nj.lianjia.com/chengjiao/gulou", name: "gulou", size: 2 }, // 测试用 { url: "https://nj.lianjia.com/chengjiao/gulou", name: "gulou", size: 30 }, { url: "https://nj.lianjia.com/chengjiao/jianye", name: "jianye", size: 20 }, { url: "https://nj.lianjia.com/chengjiao/qinhuai", name: "qinhuai", size: 29, }, { url: "https://nj.lianjia.com/chengjiao/xuanwu", name: "xuanwu", size: 14 }, { url: "https://nj.lianjia.com/chengjiao/yuhuatai", name: "yuhuatai", size: 14, }, { url: "https://nj.lianjia.com/chengjiao/qixia", name: "qixia", size: 14 }, { url: "https://nj.lianjia.com/chengjiao/jiangning", name: "jiangning", size: 40, }, { url: "https://nj.lianjia.com/chengjiao/pukou", name: "pukou", size: 25 }, { url: "https://nj.lianjia.com/chengjiao/liuhe", name: "liuhe", size: 4 }, { url: "https://nj.lianjia.com/chengjiao/lishui", name: "lishui", size: 4 },];// 南京各区成交数据const nanJin = async (page) => { for (let i = 0; i < mapAreaPageSize.length; i++) { const areaLines = await nanJinArea(page, mapAreaPageSize[i]); // 分区写入csv await saveContent(  `./output/lianjia`,  `${mapAreaPageSize[i].name}.csv`,  areaLines.join("\n") ); }};const nanJinArea = async (page, m) => { let areaLines = []; for (let i = 1; i <= m.size; i++) { await page.goto(`${m.url}/pg${i}`); // 等待页面加载完成,这是显示总套数的div await page.$$("div>.total.fs"); await mouseDown(page, 800, 10); // 解析页面内容 const lines = await parseLianjiaData(page); areaLines = areaLines.concat(lines); // 保存页面内容 await savePage(page, `./output/lianjia/${m.name}`, `page-${i}.html`); } return areaLines;};// 解析页面内容// 1. name: 小区名称和房屋概要// 2. houseInfo: 房屋朝向和装修情况// 3. dealDate: 成交日期// 4. totalPrice: 成交价格(单位: 万元)// 5. positionInfo: 楼层等信息// 6. unitPrice: 成交单价// 7. advantage: 房屋优势// 8. listPrice: 挂牌价格// 9. dealCycleDays: 成交周期const parseLianjiaData = async (page) => { const listContent = await page.$$(".listContent>li"); let lines = []; for (let i = 0; i < listContent.length; i++) { try {  const name = await listContent[i].$eval(  ".info>.title>a",  (node) => node.innerText  );  const houseInfo = await listContent[i].$eval(  ".info>.address>.houseInfo",  (node) => node.innerText  );  const dealDate = await listContent[i].$eval(  ".info>.address>.dealDate",  (node) => node.innerText  );  const totalPrice = await listContent[i].$eval(  ".info>.address>.totalPrice>.number",  (node) => node.innerText  );  con......

原文转载:http://www.shaoqun.com/a/838156.html

跨境电商:https://www.ikjzd.com/

reddit:https://www.ikjzd.com/w/180

五洲会海购:https://www.ikjzd.com/w/1068

pocket:https://www.ikjzd.com/w/1903


概述最近在学习python的各种数据分析库,为了尝试各种库中各种分析算法的效果,陆陆续续爬取了一些真实的数据来。顺便也练习练习爬虫,踩了不少坑,后续将采集的经验逐步分享出来,希望能给后来者一些参考,也希望能够得到先驱者的指点!采集工具其实基本没用过什么现成的采集工具,都是自己通过编写代码来采集,虽然耗费一些时间,但是感觉灵活度高,可控性强,遇到问题时解决的方法也多。一般根据网站的情况,如果提供AP
telegram:https://www.ikjzd.com/w/1734
marks spencer:https://www.ikjzd.com/w/2385
亚马逊更新个人身份信息的隐私政策、推出新个性化时尚服务:https://www.ikjzd.com/articles/103139
阿里巴巴国际站物流泉州开仓 ,设3条专线!:https://www.ikjzd.com/articles/103140
出货到这个国家的卖家注意!该国即将"九连休"!:https://www.ikjzd.com/articles/103141
亚马逊广告没用?那是你不知道这个数据!:https://www.ikjzd.com/articles/103144
男生㖭我大腿中间的东西 拨开我的内裤坐了下来:http://lady.shaoqun.com/a/248372.html
舌头伸进去里面吃小豆豆 使劲添啊添的流水了:http://lady.shaoqun.com/a/248217.html
《色戒》梁朝伟舔汤唯的牛奶据说是一把真正的刀:http://lady.shaoqun.com/a/393608.html
美国流氓律所碰瓷中国卖家商标侵权,被冻结3000万:保护好商标才能杜绝"钓鱼执法":https://www.ikjzd.com/articles/146251
IOSS不是强制,没有IOSS如何清关发货?:https://www.ikjzd.com/articles/146250
女生第一次有多痛?这篇文章告诉你答案:http://lady.shaoqun.com/a/393609.html

没有评论:

发表评论