使用DomCrawler抓取7W+房天下中介信息

2018年05月26日15:08:51 实习第四周 XXM

本周要求为LinXin项目爬取房地产中介代理人信息.

正文:

1.获取所有城市的Domain

入口URL:http://www.fang.com/SoufunFamily.htm

2018-05-26 14-08-57屏幕截图.png

首先我们需要获取到所有城市的URL,我们通过查看HTML发现所有字母排序下的城市都存放在<p class="outCont" id="c02">中,我们首先用DomCrawler解析出我们对应的城市URL.

$url       = 'http://www.fang.com/SoufunFamily.htm';
        $Crawl     = $this->client->request('GET', $url);
        $cityCount = 0;
        $citys     = $Crawl->filter('#c02 a')->each(function ($node, $cityCount) {
            if ($cityCount < 652) {
                $cityCount++;
                return str_replace('http://', 'http://esf.', $node->attr('href')) . 'agenthome/';
            }
        });

以上我们便成功获取到了所有城市的信息,按照要求我们只需要获取前面652个国内城市的房产中介代理人信息,所以我们声明了一个变量$CityCount来作为判断条件,然后将符合条件的城市URL存入到数组中,但是Crawler中的each方法会默认返回空,所以不满足的条件的城市,也会返回一个空到数组当中,所以需要对数组进行处理,我们通过PHP系统函数array_filter()来过滤掉我们数组的空值部分.

 $citys = array_filter($citys);

当成功取得所有国内城市的URL后,便可以对城市的房地产中介信息进行抓取,但在测试中,由于网络波动的原因,爬虫会出现中断的情况,所以我们在向对应url页面进行抓取之前,也请求对应当前URL的http状态,这里我通过一个自定义函数httpcode()来发送请求.

public function httpcode($url)
    {
        $ch      = curl_init();
        $timeout = 10;
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_exec($ch);
        return $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    }

当我们获得当前URL状态为200时,我们便对当前页面进行爬取.

public function getContent($url)
    {
        if ($this->httpcode($url) != "200") {
            return;
        }
        $Crawl = $this->client->request('GET', $url);
        $html  = $Crawl->count() ? $Crawl->html() : $this->error("crawl爬空了");

        // echo $html;
        if (empty($html)) {
            $this->info("无效");
            return;
        }
        $this->getDetail($url, $html);
    }

    public function getDetail($url, $html)
    {
        if ((strpos($html, '全部经纪人')) && (!strpos($html, '很抱歉,没有找到相符的经纪人!'))) {
            $Crawl = new Crawler();
            //echo $url;
            $Crawl->addHtmlContent($html);
            $last_Page = $Crawl->filter('.txt')->text();
            $last_Page = str_replace('共', '', $last_Page);
            $last_Page = str_replace(' 页', '', $last_Page);
            $pageUrls  = [];
            for ($i = 1; $i <= $last_Page; $i++) {
                $pageUrls[] = "$url-i3$i-j310/";
            }
            $citys       = "";
            $curentIndex = 1;
            foreach ($pageUrls as $page) {
                $Crawl = $this->client->request('GET', $page, ['connect_timeout' => 10]);
                if (!isset($Crawl)) {
                    dd($page);
                }
                $agentNames = $Crawl->filter('.ttop')->each(function ($node) {
                    return $this->stripTextNull($node->text());
                });
                $agentTels = $Crawl->filterXPath('//p[@class="gray3 f14 liaxni"]')->each(function ($node) {
                    return $node->text();
                });
                $agentCompanys = $Crawl->filterXPath('//span[@class="gray3 fl"]')->each(function ($node) {
                    return $this->stripTextNull($node->text());
                });
                $citys = count($Crawl->filter('.s4Box')) > 0 ? $Crawl->filter('.s4Box')->first()->text() : "无法获取";

                $this->importData($agentNames, $agentTels, $agentCompanys, $citys);

                $this->info($citys . '当前进度:' . $curentIndex . '剩余进度' . ($last_Page - $curentIndex));
                $curentIndex++;
            }
            $this->info($citys . " get success");
        }
    }

当我们成功采集了所需的信息之后,就需要把数据Upload到数据库当中.

public function importData(array $names, array $Tels, array $Companys, $city)
    {
        $count = count($names);
        for ($i = 0; $i < $count; $i++) {
            $agent = Agent::firstOrNew([
                'phone' => $Tels[$i],
            ]);

            $agent->name    = $names[$i];
            $agent->company = $Companys[$i];
            $agent->city    = $city;
            $agent->user_id = 35;

            $agent->save();

            $this->info("$agent->name ,上传成功,电话号码为:$agent->phone");
        }
    }

最后我们成功抓取到了75040条数据.

2018-05-26 14-44-10屏幕截图.png

全部代码:

<?php
namespace App\Console\Commands\Crawlers;

use App\Agent;
use Goutte\Client;
use Illuminate\Console\Command;
use Symfony\Component\DomCrawler\Crawler;

class CrawlAgent extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'crawl:lxagent';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '邻信中介信息';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->client = new Client();
        $this->client->setHeader('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36');
        $agentNames    = [];
        $agentTels     = [];
        $agentCompanys = [];
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
        $this->CrawlMain();
    }

    public function getList()
    {
        $url       = 'http://www.fang.com/SoufunFamily.htm';
        $Crawl     = $this->client->request('GET', $url);
        $cityCount = 0;
        $citys     = $Crawl->filter('#c02 a')->each(function ($node, $cityCount) {
            if ($cityCount < 652) {
                $cityCount++;
                return str_replace('http://', 'http://esf.', $node->attr('href')) . 'agenthome/';
            }
        });
        $citys = array_filter($citys);
        $this->info("city is success");
        return $citys;
    }

    public function getContent($url)
    {
        if ($this->httpcode($url) != "200") {
            return;
        }
        $Crawl = $this->client->request('GET', $url);
        $html  = $Crawl->count() ? $Crawl->html() : $this->error("crawl爬空了");

        // echo $html;
        if (empty($html)) {
            $this->info("无效");
            return;
        }
        $this->getDetail($url, $html);
    }

    public function getDetail($url, $html)
    {
        if ((strpos($html, '全部经纪人')) && (!strpos($html, '很抱歉,没有找到相符的经纪人!'))) {
            $Crawl = new Crawler();
            //echo $url;
            $Crawl->addHtmlContent($html);
            $last_Page = $Crawl->filter('.txt')->text();
            $last_Page = str_replace('共', '', $last_Page);
            $last_Page = str_replace(' 页', '', $last_Page);
            $pageUrls  = [];
            for ($i = 1; $i <= $last_Page; $i++) {
                $pageUrls[] = "$url-i3$i-j310/";
            }
            $citys       = "";
            $curentIndex = 1;
            foreach ($pageUrls as $page) {
                $Crawl = $this->client->request('GET', $page, ['connect_timeout' => 10]);
                if (!isset($Crawl)) {
                    dd($page);
                }
                $agentNames = $Crawl->filter('.ttop')->each(function ($node) {
                    return $this->stripTextNull($node->text());
                });
                $agentTels = $Crawl->filterXPath('//p[@class="gray3 f14 liaxni"]')->each(function ($node) {
                    return $node->text();
                });
                $agentCompanys = $Crawl->filterXPath('//span[@class="gray3 fl"]')->each(function ($node) {
                    return $this->stripTextNull($node->text());
                });
                $citys = count($Crawl->filter('.s4Box')) > 0 ? $Crawl->filter('.s4Box')->first()->text() : "无法获取";

                $this->importData($agentNames, $agentTels, $agentCompanys, $citys);

                $this->info($citys . '当前进度:' . $curentIndex . '剩余进度' . ($last_Page - $curentIndex));
                $curentIndex++;
            }
            $this->info($citys . " get success");
        }
    }

    public function CrawlMain()
    {
        $urls = $this->getList();
        foreach ($urls as $cityUrl) {
            $this->getContent($cityUrl);
        };
        for ($i = 0; $i < count($agentNames); $i++) {
            $this->info($agentNames[$i] . '---' . $agentTels[$i] . '---' . $agentCompanys[$i]);
        }
    }
    public function stripTextNull($str)
    {
        $str = str_replace('\t', '', $str);
        $str = str_replace('\n', '', $str);
        $str = str_replace('\r', '', $str);
        $str = trim($str);
        return $str;
    }

    public function importData(array $names, array $Tels, array $Companys, $city)
    {
        $count = count($names);
        for ($i = 0; $i < $count; $i++) {
            $agent = Agent::firstOrNew([
                'phone' => $Tels[$i],
            ]);

            $agent->name    = $names[$i];
            $agent->company = $Companys[$i];
            $agent->city    = $city;
            $agent->user_id = 35;

            $agent->save();

            $this->info("$agent->name ,上传成功,电话号码为:$agent->phone");
        }
    }

    public function httpcode($url)
    {
        $ch      = curl_init();
        $timeout = 10;
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_exec($ch);
        return $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    }

}

summary:

本次爬取该网站数据中,遇到很多以前没有遇到过的问题,如页面数据乱码,网络请求超时,手动入库,最后在聪哥的指导下成功地解决了这些问题.

2018年05月26日15:40:50

日记本

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

赞赏支持
被以下专题收入,发现更多相似内容