赞
踩
本文全面解析了链家新房源数据,爬取了全部城市的房源信息,共两万六千条数据
提示:以下是本篇文章正文内容,下面案例可供参考
这个url的构成很简单,https://后面是城市的首字母 pg后表示页数。我们为了拿到所有城市的房源数据,需要构造出准确无误的所有url 有了url利用request进行访问
现在我们有两个部分是必须要获取的 一个是拿下所有城市的首字母,一个是拿下对应城市的页数
https://bj.fang.lianjia.com/loupan/pg1/
这样的话问题就来了,去哪里获取城市的首字符和对应的页数呢,我们打开他的首页看一看,点击圈中的按钮之后就会出现所选的城市,我们可以通过这些城市拿到对应的首字母
我们右键检查元素,每个城市对应的就是每个城市房源数据的url,我们拿到他们的url提取出首字符就可以了
现在有了首字符,还缺对应城市的页数,我的方法是利用selenium访问每个url然后拿到他们的总页数
每个页数对应一个a标签,当存在两个及两个以上页数时我们那他倒数第二个a标签(有下一页按钮)
当仅仅只有一页时我们就直接让他等于1(没有下一页按钮)
根据上文我们有了思路现在我们就去实现代码
基本配置
代码如下(示例):
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu') #设置无头浏览器
prefs = {'profile.managed_default_content_settings.images': 2}
chrome_options.add_experimental_option('prefs', prefs) # 禁止图片加载,加快速度
bro = webdriver.Chrome(options=chrome_options)#实例化对象
})
先顺顺思路,我们进入页面之后要干啥
我们在点击城市按钮后出现了城市列表 获取城市首字符,在我们点击第三步筛选后我们获取最大页数
有了这个思路现在我们写代码
打开网页 定位所有城市列表
bro.get('https://bj.fang.lianjia.com/')#打开网页
#城市列表
li_list=bro.find_elements_by_xpath("/html/body/div[3]/div[3]//a")
定位每个元素循环点击,点击 --》点击筛选 --》退回 --》点击
因为每次退回主页页面重新的刷新,所以每次循环最后在从新获取li_list
获取最大页数的代码位置一定要在指定的位置,只有切换到房源页是才能找到最大页数
for i in range(len(li_list)):
bro.find_element_by_xpath("/html/body/div[1]/div/div[1]/a[2]").click() # 点击城市按钮
li_list[i].click() #点击城市
#在这获取页面首字符
bro.find_element_by_xpath('//div[@data-search-position="search_result"]').click() #点击筛选
ws = bro.window_handles # 当前所有页面
bro.switch_to.window(ws[1]) # 切换新页面,房源页
#在这获取最大页数,并保存数据
bro.close() #关闭房源页
bro.switch_to.window(ws[0]) # 回到主页
li_list=bro.find_elements_by_xpath('/html/body/div[3]/div[3]//a')
页面首字符代码,我还多加了一个城市名称
dic["city"]=li_list[i].get_attribute("href").replace(".fang.lianjia.com/","").replace("https://","") # 城市首字母
dic["city_name"]=li_list[i].text #每个城市
最大页数、保存数据代码
当数据存在多个页数时是有“下一页”这个按钮的,当只有一页时是不存在“下一页”按钮,以此判断页数,最后边爬边保存
if "下一页" in bro.page_source:
dic["page"]=bro.find_element_by_xpath('//div[@class="page-box"]/a[last()-1]').text #最多页数
else:
dic["page"]="1"
with open(".//city_page.csv", "a", encoding="utf-8") as f:
writer = csv.DictWriter(f, dic.keys())
writer.writerow(dic)
我们获取了最大page、和首字符现在开始拼接url
names=["city","name","page"]
df=pd.read_csv("city_page.csv",names=names) #读入数据
df.page=df.page.map(lambda x:re.findall("(\d+)",str(x))[0]) #提取出页数
for a, b in zip(df.city, df.page):
for i in range(int(b)):
url = "https://%s.fang.lianjia.com/loupan/pg%d/" % (a, i+1) #拼接url
#保存url为txt
with open("urls.txt","a",encoding="utf-8") as f:
f.write(url)
f.write("\n")
到此为止,所有城市的url全部拼接完毕,一共有2669条url,有了这些 我们就可以用requests多线程快速的爬取数据了
有了url,现在我们来解析一下页面数据,我们要拿下名称、地址、价格、类型等等数据
右键检查元素我们知道,房源数据都在ul标签的li标签里,每一个li对应一个房源
这样我们就可以利用Xpath定位获取数据,代码没有加try 应该加上try 因为有的数据在列表中是不存在的
li_list=html.xpath('//ul[@class="resblock-list-wrapper"]/li')
for li in li_list:
dic={}
dic["title"]=li.xpath('./div//div[@class="resblock-name"]/a/text()')[0]
dic["type"]=li.xpath('./div//span[@class="resblock-type"]/text()')[0]
dic["status"]=li.xpath('./div//span[@class="sale-status"]/text()')[0]
dic["location"]=''.join([x for x in li.xpath('./div//div[@class="resblock-location"]//text()') if '\n' not in x])
dic["room"]=''.join([x for x in li.xpath('./div//a[@class="resblock-room"]//text()') if '\n' not in x])
dic["area"]=li.xpath('.//div[@class="resblock-area"]/span/text()')[0]
dic["tag"]=''.join([x for x in li.xpath('./div//div[@class="resblock-tag"]//text()') if '\n' not in x])
dic["main_price"]=li.xpath('./div//div[@class="main-price"]/span[@class="number"]/text()')[0]
dic["price"]=li.xpath('./div//div[@class="resblock-price"]/div[@class="second"]/text')[0]
dic["img_link"]=li.xpath('./a//img[@class="lj-lazy"]/@src')[0]
location、area、tag三个数据获取到的都是列表所以在获取时剔除掉无用字符,并且连接为字符串
''.join([x for x in li.xpath('./div//div[@class="resblock-tag"]//text()') if '\n' not in x])
list=[]
for x in li.xpath('./div//div[@class="resblock-tag"]//text()'):
if "\n" not in x:
list.append(x)
''.join(list)
读取url 因为我们上步已经保存了url为txt 现在我们读入url
urls = open("urls.txt", "r", encoding="utf-8").read()
urls=urls.split("\n")[:-1] #根据换行符分割 转换为列表
保存数据,这个应放在循环li_list中,边爬边存
with open(".//fangyuan.csv", "a", encoding="utf-8") as f:
writer = csv.DictWriter(f, dic.keys())
writer.writerow(dic)
最后可以开启线程池快速的爬取数据
pool = Pool(4)
pool.map(parser_data,urls)
采集完成之后看一下效果,有5MB多
去重之后数据有将近3W条,10个字段
到这里这篇文章就结束了,如果你对爬虫有兴趣,可以关注我的主页 近期再写一些爬虫项目,主页中已经更新了多个爬虫。
本文章用到的代码在公众号“阿虚学Python”中回复“链家”获取,还有更多爬虫项目等你来看哦
谢谢大家的观看,如果觉得这篇文章不错就点个赞支持一下吧
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。