python 爬虫-链家租房信息
爬虫,其实就是爬取web页面上的信息。
链家租房信息页面如下:
https://gz.lianjia.com/zufang/
## python库
Python库
1.request 用来获取页面内容
2.BeatifulSoup
request文档链接:
https://requests.readthedocs.io/zh_CN/latest/user/quickstart.html
BeatifulSoup文档链接:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
先安装这两个包
安装requests和BeautifulSoup:
跟上篇同样的方法,安装成功的界面如下:
安装代码:
pip install requests
代码:
pip install bs4
同样检查一下:
代表安装成功了。
遇到问题:python还是无法识别requests库。百度了一下。解决办法如下:
打开Python文件的安装目录,进入Scripts文件中,按住Shift键+鼠标右击,选择【在此处打开Powershell窗口】
可以看到,requests的确存在了。
此时进入python,点击file-settigngs,选择【Project Interpreter】,在右边的列表里可以看到已经安装的各种库、对应的版本以及最新版本,然后点击 + 号,搜索报错的那个库,比如本文的 requests 库,选中后点击【Install Package】安装库,安装成功后右下角会有提示 Packages installed successfully,再次运行程序就没有报错了!
同理下载bs4。
运行结果:
原博:
https://blog.youkuaiyun.com/qq_36759224/article/details/100026277
import requests
from bs4 import BeautifulSoup
url = "https://gz.lianjia.com/zufang/"
responce = requests.get(url)
soup = BeautifulSoup(responce.text,'lxml')
# print(responce.text)
print(soup)
运行时报错:
bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
解决:原因是没有下载lxml需要的东西,下载一个就好了。
下载完之后,
from bs4 import BeautifulSoup
是不报错了,但是运行之后还是报错,把lxml改为html.parser,运行结果没有问题!
import requests
from bs4 import BeautifulSoup
url = "https://gz.lianjia.com/zufang/"
responce = requests.get(url)
soup = BeautifulSoup(responce.text,'html.parser')
# print(responce.text)
print(soup)
原博:
https://blog.youkuaiyun.com/weixin_44024857/article/details/87904685
打开网页,右键,检查,看到这行颜色变了,找到div class的名字是content__list–item–main。
代码这么写:
links_div = soup.find_all('div', class_="content__list--item--main")
# links = [for div in links_div]
print(links_div) #里面存了一个列表
# print(links_div[0]) #查看第一个
# print(links)
运行结果:
查看列表其中一个元素,这里查看第一个:
但是我们只想要链接,不要图片等其他的信息,也就是a href后面的链接,代码如下:
links_div = soup.find_all('div', class_="content__list--item--main")
links = [div.a.get('href') for div in links_div]
# print(links_div) #里面存了一个列表
# print(links_div[0].a.get('href')) #查看第一个
print(links,len(links))
此时,我们就获取到了当前页面的全部链接,长度为33。
封装成函数,作用是获取列表页下面的所有租房页面的链接,返回一个链接列表
def get_links(url):
responce = requests.get(url)
soup = BeautifulSoup(responce.text, 'html.parser')
links_div = soup.find_all('div', class_="content__list--item--main")
links = [div.a.get('href') for div in links_div]
return links
url = "https://gz.lianjia.com/zufang/"
print(get_links(url))
结果相同:
['/zufang/GZ2298305088701612032.html', '/zufang/GZ2381801160471756800.html', '/zufang/GZ2359884100317757440.html', '/apartment/7268.html', '/zufang/GZ2499974203789549568.html', '/apartment/19264.html', '/zufang/GZ2499100907166777344.html', '/zufang/GZ2499209752543248384.html', '/zufang/GZ2497822820261183488.html', '/zufang/GZ2497607240542846976.html', '/zufang/GZ2498431143112876032.html', '/zufang/GZ2310049470823809024.html', '/zufang/GZ2499346361594953728.html', '/zufang/GZ2392521977211928576.html', '/zufang/GZ2499056259253411840.html', '/zufang/GZ2500010005773172736.html', '/zufang/GZ2500031132138217472.html', '/zufang/GZ2499288504467996672.html', '/zufang/GZ2499020325493145600.html', '/zufang/GZ2499120229419065344.html', '/zufang/GZ2499377558819717120.html', '/zufang/GZ2378856616616534016.html', '/zufang/GZ2497621306694959104.html', '/zufang/GZ2330296981744271360.html', '/zufang/GZ2497812365010010112.html', '/zufang/GZ2354164126701592576.html', '/zufang/GZ2497645065968041984.html', '/zufang/GZ2334517367570710528.html', '/zufang/GZ2321645290765434880.html', '/zufang/GZ2362854688652525568.html', '/zufang/GZ2344044030008238080.html', '/zufang/GZ2325288593729257472.html', '/zufang/GZ2354875364645543936.html']
点进其中一个页面,https://gz.lianjia.com/zufang/GZ2298305088701612032.html?nav=0&unique_id=dd85aae4-ba2d-46af-a027-1b5a920a1b70zufang1589621537856,检查元素,点击图片左上角的箭头,这样我们点到页面哪个地方,都会相对应定为到查看器哪个地方。比如点到租金2000元,定位到了<span>
那一行,没有class,怎么办呢?试着把class写成上一行的content__aside–title,结果可以爬到,可是多了一些,用字符串截取一下。
接下来一点点提取面积、楼层等信息。
租金
点到租金2000元,定位到了<span>
那一行,没有class,怎么办呢?试着把class写成上一行的content__aside–title,结果可以爬到,可是多了一些,用字符串截取一下。
# 获取url下的页面内容,返回soup对象
def get_page(url):
responce = requests.get(url)
soup = BeautifulSoup(responce.text, 'html.parser')
return soup
# 封装成函数,作用是获取列表页下面的所有租房页面的链接,返回一个链接列表
def get_links(link_url):
soup = get_page(link_url)
links_div = soup.find_all('div', class_="content__list--item--main")
links = [div.a.get('href') for div in links_div]
return links
house_url = 'https://gz.lianjia.com/zufang/GZ2298305088701612032.html?nav=0&unique_id=' \
'dd85aae4-ba2d-46af-a027-1b5a920a1b70zufang1589621537856'
soup = get_page(house_url)
# print(soup.find('div', class_='content__aside--title').text)
price = soup.find('div', class_='content__aside--title').text
print(price[1:8])
.text可以打印出我们真正想要获取的文本。运行结果:
最后把这个结果赋值给price。截取后刚好爬到租金!
因为这里的单位已经跟价格一起显示了,所以不用单独再写代码爬了。如果要写的话,跟价格时一样的,比如
# unit = soup.find('span', class_='total').text
# unit.strip()
合并:
unit = soup.find('span', class_='total').text.strip()
意思是一样的。strip函数可以把两边的空格删除。
面积:
点击面积,定位到下图的地方,是一个列表的样式,这时我们find_all就好了。
代码如下:
house_info = soup.find_all('li',class_='fl oneline')
print(house_info)
打印house_info看一下:
所有的租房信息都出现了。
但我们只要文本,打印住房面积看一下:
print(house_info[1].text)
结果:
但是“面积:”这三个字符我们是不需要的,截取掉:
print(house_info[1].text[3:])
结果:
把面积赋给area
area = house_info[1].text[3:]
朝向
第二个信息是朝向,同样的代码:
chaoxiang = house_info[2].text[3:]
结果:
没有问题!
维护
第三个是维护。
入住
同上。
chaoxiang = house_info[2].text[3:]
weihu = house_info[4].text[3:]
ruzhu = house_info[5].text[3:]
louceng = house_info[7].text[3:]
dianti = house_info[8].text[3:]
print(chaoxiang, weihu, ruzhu, louceng)
暂时爬这几个。
租赁方式
自己试着爬了租赁方式这块的信息,定位到检查元素,同样是find_all
如果把class成label,只要爬到下图:
试了一下把class写成content__aside__list,也就是蓝色的地方。
lease = soup.find_all('ul', class_='content__aside__list')
# lease = soup.find_all('span', class_='label')
print(lease)
这样才能爬到完整的信息。
在后面加上text想只保留文字
注意!不能直接lease.text,因为lease是find_all出来的一个列表,不是find函数,如果是price就可以直接在后面加 .text
price = soup.find('div', class_='content__aside--title').text
但是find_all不行,要先指定其中一个元素:
lease = soup.find_all('ul', class_='content__aside__list')
# lease = soup.find_all('span', class_='label')
print(lease[0].text)
这样文字就出来了:
同样的,"租赁方式:"这五个字符不需要,截取掉:
print(lease[0].text[6:])
这样打印出来的就是整租两个字了。
这里因为lease[0]就是全部文字,所以一个个截取出来。
print(lease[0].text[6:9],lease[0].text[14:25],lease[0].text[30:40])
结果:
把所有信息打印看一下:
info = {
'价格':price,
'面积':area,
'朝向':chaoxiang,
'维护':weihu,
'入住':ruzhu,
'楼层':louceng,
'电梯':dianti,
'租赁信息':lease_info
}
print(info)
结果:
{'价格': '2000元/月', '面积': '73㎡', '朝向': '东北', '维护': '今天', '入住': '随时入住', '楼层': '高楼层/6层', '电梯': '无', '租赁信息': ('整租\n', '2室1厅1卫 73㎡\n', '东北 高楼层/6层\n')}
对房屋信息进行封装
1.先在navicat把表格建好
2.把连接数据库函数也封装一下
DATABASE = { #一个数据库,写成字典;如果是多个数据库连接,写成列表[{配置信息},{}]
'host':'localhost', #localhost相当于127.0.0.1,如果是远程数据库,此处为远程服务器的ip地址
'database':'lj',
'user':'root',
'password':'1234'
}
def get_db(setting):
return pymysql.connect(**setting)
def insert(db, house):
values = "'{}',"*7 +"'{}'"
sql_values = values.format(house['价格'],house['面积'],house['朝向'],house['维护'],
house['入住'],house['楼层'],house['电梯'],house['租赁信息'])
sql = """
insert into house(price,area,chaoxiang,weihu,ruzhu,louceng,dianti,lease_info)
values({});
""".format(sql_values)
print(sql)
cursor = db.cursor()
cursor.execute(sql)
db.commit()
3.插入数据库
house = get_house_info('https://gz.lianjia.com/zufang/GZ2298305088701612032.html?'
'nav=0&unique_id=dd85aae4-ba2d-46af-a027-1b5a920a1b70zufang1589621508886')
# print(house)
db = get_db(DATABASE)
insert(db,house)
因为租赁信息是个元组,插入数据库总是报错,我改成了text,把没有截取的整段文字传进去了。如图:
4.爬取多条信息
db = get_db(DATABASE)
links = get_links('https://gz.lianjia.com/zufang/')
for link in links:
time.sleep(2)
print("获取一个房子信息成功")
house = get_house_info(link)
# print(house, end='\r')
insert(db,house)
最后爬取成功
源代码:
https://github.com/CSU-liujie/wanmen/blob/master/%E7%88%AC%E8%99%AB-%E9%93%BE%E5%AE%B6%E7%A7%9F%E6%88%BF%E4%BF%A1%E6%81%AF