前言
最近学习了一下python3.5中爬虫的原理套路!
之前写demo的时候,获取html源码后一直在使用python自带的re模块来用正则表达式匹配数据。
不得不说!正则很强大!(强大的.*?,笑),各种复杂的情况下都可以匹配的到,但是写法非常灵活,每个人的思维模式不一样,写出来也就不一样,对于没有接触过正则表达的同学来说,学习成本还是需要一写的!
所以今天来说一下对于我这种正则小白的福音!python下提供的一个基于正则的模块,xpath,使用节点的概念来匹配你所获取到的页面源码!超级好用!
[xpath菜鸟教程学习传送门]:点击打开链接
今天用xpath写了一发get 58同城租房信息的demo,下面附上流程和code
A.实现思路
58同城首页->租房->北京出租
首先我们得到的是一个这样的页面
点进去之后得到这样一个页面
那么我们爬取信息的套路就可以初步确定下来了!
1.首先在房源信息列表页面循环分页获取到每篇独立的房源帖子url,也就是a标签中的href。
2.接着我们需要循环向这些帖子的url发起网络请求(使用requests模块或自带urllib模块都可以啦~)获取每篇帖子的html源码
3.获取每篇帖子的源码后!我们就可以分析源码的结构,然后使用xpath(代码中实际引用的是lxml这个文件)进行匹配数据,获取到我们需要的信息了!
4.获取每个房源的信息,并把图片都存储下来!
B.获取到的数据
1.房源json信息
2.房源图片的存储
C.实现代码
from urllib import request #lxml就是xpath的模块 from lxml import etree import requests,json,time #爬取一级列表网页信息 def get_pages(page_num): #确认目标 target = 'http://bj.58.com/chuzu/?PGTID=0d3090a7-0000-1299-6863-0094cd8364e7&ClickID={}'.format(page_num) #发起网络请求 response = requests.get(target) response.encoding = 'utf-8' #获取html源码 html = response.text #使用lxml进行数据匹配 html = etree.HTML(html) #获取房源信息,进入单个帖子的url url_lists = html.xpath('//div[@class="listBox"]//h2//@href') for url in url_lists: get_page_info(url) time.sleep(2) #爬取二级详情页面信息 def get_page_info(url): response = requests.get(url) response.encoding = 'utf-8' page_code = response.text #储存房源信息dict house_info house_info = {} html = etree.HTML(page_code) #房源信息标题 title = html.xpath('//div[@class="house-title"]/h1/text()') if title: house_info['title'] = title[0] #月租 pay_month = html.xpath('//div[@class="house-pay-way f16"]//b/text()') if pay_month: house_info['pay_month'] = pay_month[0] #租赁方式 pay_type = html.xpath('//ul[@class="f14"]/li[1]/span[2]/text()') if pay_type: house_info['pay_type'] = pay_type[0] #房屋类型 house_type = html.xpath('//ul[@class="f14"]/li[2]/span[2]/text()') if house_type: house_info['house_type'] = house_type[0].strip() #朝向楼层 house_dxnb = html.xpath('//ul[@class="f14"]/li[3]/span[2]/text()') if house_dxnb: house_info['house_dxnb'] = house_dxnb[0] #所属区域 house_location = html.xpath('//ul[@class="f14"]/li[4]/span[2]/text()') if house_location: house_info['house_location'] = house_location[0] #详细地址 house_adress = html.xpath('//ul[@class="f14"]/li[6]/span[2]/text()') if house_adress: house_info['house_adress'] = house_adress[0].strip() #销售员名称 agent_name = html.xpath('//p[@class="agent-name f16 pr"]//text()') if agent_name: house_info['agent_name'] = agent_name[0].strip() #销售员电话 agent_phone = html.xpath('//span[@class="house-chat-txt"]/text()') if agent_phone: house_info['agent_phone'] = agent_phone[0] #房屋特点 house_special = html.xpath('//ul[@class="introduce-item"]/li[1]//span[2]/em/text()') if house_special: house_info['house_special'] = house_special #房源描述 house_des = html.xpath('//ul[@class="introduce-item"]/li[2]//p/span/text()') if house_des: house_info['house_des'] = house_des #房屋描述图片 pic_urls = html.xpath('//ul[@id="housePicList"]/li/img/@lazy_src') #循环截取出图片的名称 img_list = [] for url in pic_urls: first_url = url.split('?') pic_name = first_url[0].split('/')[-1] + '.jpg' img_list.append(pic_name) #图片名称存入house_info中 house_info['house_imgs'] = img_list #下载图片 request.urlretrieve(url,'./images/'+ pic_name) with open('./house.json','a',encoding='utf-8') as f: #json.dumps()-> dict转json f.write(json.dumps(house_info,ensure_ascii=False) + '\n') #打印结果 print(house_info) if __name__ == '__main__': #循环页数 for page_num in range(1,2): get_pages(page_num)
D.注意事项
1.demo中只爬取了一页的房源信息,如需更改请修改主进程中的for in循环range值
2.如果有使用fiddler或者Charless这样抓包工具的同学,在跑demo的时候请先关闭一下,否则会报一个http error 504的错误
[http error 504 大神错误解决方案传送门]:点击打开链接