爬取10w条链家租房数据

爬取10w条链家租房数据

一.背景

  • 由于女票的工程实践选了python数据分析,要分析北上广深的租房现状,而后我就只能扒拉一下之前的python代码,看看能不能爬个几万条数据给她分析(感受都是老生常谈的分析了~)
  • 由于我是作前端的,因此网页数据解析使用的是pyquery这个库,使用语法有点像jquery
  • 而且这个项目可能会成为毕业设计,因此我尽可能使用多种方式。例如地区数据使用csv文件存放,租房详情数据使用pymysql存放;地区url使用selenium获取,而详情数据使用requests进行获取

二.分析

  • 以深圳为例,链家租房的网址是:https://sz.lianjia.com/zufang/ ; 从而一个个去看北上广深,获得城市数组 ['sz','sh','bj','gz']
  • 分析深圳翻页接口:https://sz.lianjia.com/zufang/pg100/#contentList;当页数大于100的时候,获得的数据仍是和100页的时候同样,因此改变pg后面的数字是没法获得全部数据的
  • 思考:一个城市分为多个区,一个区分为多个街道之类的,那么每一个街道的页数上限也是100的话,那么即便偶尔有一两个超过100页的街道,获得的数据量也是远大于咱们100页的数据量

三.问题

  • 在实际编码中遇到了一些问题
  • 获取到的数据中存在必定数量的广告:通过观察发现广告没有对应房子地址的元素,因此经过这个判断是不是广告,若是是广告则爬取下一条数据
  • 链家反爬策略: 链家的反爬相对来讲仍是很友好的,即便被抓到了,人机验证几回就又能够了,因此我这里只是经过time.sleep()休眠方式来进行反反爬。有钱的朋友能够去淘宝买ip弄个ip池,这样啥反爬都不慌了,至于那些免费ip的网站基本没啥用。
  • 爬到一半结果被反爬:个人解决方案比较low,就是手动把csv文件中已经用到的url删除,下一次运行就去爬剩下还没爬取的数据

四.实现

  1. 首先创建数据库表
  • 在navicat建立数据库lianjia,建立表的语句以下:
create table shanghai(
  id int(5) PRIMARY KEY NOT NULL auto_increment,
  city VARCHAR(200),
  hName VARCHAR(200),
  way VARCHAR(200),
  address VARCHAR(200) ,
  area VARCHAR(200) ,
  position VARCHAR(200),
  type VARCHAR(200),
  price VARCHAR(200),
  time VARCHAR(200),
  url VARCHAR(200)
)
复制代码
  1. 获取城市的区数据
  • 首先会在首行先导入全部依赖库
from selenium import webdriver
import time
import csv
from pyquery import PyQuery as pq
import requests
import pymysql
import random
复制代码
  • 下面的获取区的代码
def getArea():
    brow = webdriver.Chrome()
    cityArr = ['sz','sh','bj','gz']
    file = open('area.csv''a', encoding='utf-8', newline='')
    # 打开文件,准备追加内容
    writer = csv.writer(file)
    for city in cityArr:
        url = 'https://' + city + '.lianjia.com/zufang/'
        brow.get(url)
        doc=pq(brow.page_source,parser='html')
        ul=doc('#filter ul').items()
        # 得到区的url
        for item in ul:
            tem = item.attr('data-target')
            if(tem == 'area'):
                for li in item.items('li'):
                    if(li.text()!='不限'):
                        str = url.split('/zufang')[0] + li.children('a').attr('href')
                        writer.writerow(str.split(','))
        time.sleep(10)
    # 退出
    file.close()
    brow.quit()
复制代码
  1. 获取区的街道等信息
def getDetail():
    # 读
    arr = []
    with open('area.csv''r'as f:
        reader = csv.reader(f)
        for row in reader:
            arr.append(row[0])
    f.close()
    # 写
    file_detail = open('detail.csv''a', encoding='utf-8', newline='')
    writer_detail = csv.writer(file_detail)
    brow = webdriver.Chrome()
    for val in arr:
        brow.get(val)
        doc = pq(brow.page_source, parser='html')
        ul = doc('#filter ul').items()
        for i, item in enumerate(ul):
            if (i == 3):
                for li in item.items('li'):
                    if (li.text() != '不限' and li.children('a')):
                        str = val.split('/zufang')[0] + li.children('a').attr('href')
                        writer_detail.writerow(str.split(','))
                        print(str)
        time.sleep(3)
    file_detail.close()
    brow.quit()
复制代码
  1. 爬取详细租房信息
def run():
    with open('detail.csv''r'as f:
        reader = csv.reader(f)
        for row in reader:
            time.sleep(random.randint(20,100))
            pgRes = requests.get(row[0])
            pgDoc = pq(pgRes.text, parser='html')
            pgSum = int(pgDoc('.content__pg').attr('data-totalpage'))
            pg = 0
            # 还须要根据页数来进行爬取。有些再加一层循环
            while(pg < pgSum):
                pg+=1
                url =row[0] + 'pg%d'%pg
                print(url)
                res = requests.get(url)
                doc = pq(res.text, parser='html')
                city = doc('.content__title a')[0]
                str = ''
                time.sleep(random.randint(2,20))
                if(city.text == '深圳'):
                    str = 'shenzhen'
                elif(city.text == '广州'):
                    str = 'guangzhou'
                elif(city.text == '上海'):
                    str = 'shanghai'
                elif(city.text == '北京'):
                    str = 'beijing'
                else:
                    Exception('城市名称错误')

                list = doc('.content__list .content__list--item').items()
                for li in list:
                    # 须要先创建数据库,表格
                    db = pymysql.connect(host='localhost', user='root', password='123456', db='lianjia')
                    tem = li.find('.content__list--item--des')
                    arr = tem.text().split('/')
                    way = li.find('.content__list--item--title a').text().split('·')
                    house_data = (
                        city.text,
                        tem.children('a')[2].text if tem.children('a').length>1 else '广告',
                        way[0if way[0else '',
                        arr[0if arr.__len__() > 0 else '',
                        arr[1if arr.__len__() > 1 else '',
                        arr[2if arr.__len__() > 2 else '',
                        arr[3if arr.__len__() > 3 else '',
                        li.find('.content__list--item-price em').text(),
                        li.find('.content__list--item--time').text(),
                        ('https://sz.lianjia.com' + li.find('.twoline').attr('href'))if(li.find('.twoline').attr('href')) else ''
                    )
                    if(house_data[1]=='广告'):
                        continue
                    # 声明游标
                    cursor = db.cursor()
                    sql = "insert into "+ str +"(city,hName,way,address,area,position,type,price,time,url)" \
                          "  values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
                    cursor.execute(sql, house_data)
                    db.commit()  # 提交数据库
                    db.close()
复制代码

五.完整代码

  • 如今写的版本仍是比较那啥,反爬以后须要手动删除csv文件中的url,并且可能会有重复/遗漏的数据
  • 在博客园看到有大佬用移动端反编译的方式找到接口完成爬取,我还没试验过,可是看起来颇有料,有兴趣的能够去试试:https://www.cnblogs.com/mengyu/p/9115832.html
  • 由于掘金的字数限制。因此只把最后调用的代码贴上来~
if __name__=='__main__':
    getArea()
    getDetail()
    run()
复制代码
相关文章
相关标签/搜索