爬虫思路分析:
1. 观察小猪短租(北京)的网页
首页:http://www.xiaozhu.com/?utm_source=baidu&utm_medium=cpc&utm_term=PC%E6%A0%87%E9%A2%98&utm_content=pinzhuan&utm_campaign=BDPZ
选择“北京”,然后点“搜索小猪”,获取北京市的首页url:http://bj.xiaozhu.com/
观察右侧详情,页面最下面有分页,点击第2、第3页观察url的变化
http://bj.xiaozhu.com/search-duanzufang-p2-0/
http://bj.xiaozhu.com/search-duanzufang-p3-0/
验证首页是否可以写作:http://bj.xiaozhu.com/search-duanzufang-p1-0/(答案是ok的,大部分分页行的网站首页都是可以与其他分页统一化的)
因此,分页的URL可以这么构造:http://bj.xiaozhu.com/search-duanzufang-p{}-0/.format(number),其中number是几就是第几页
2. 观察右侧的信息,发现每个房源的信息不全,需要手动点击进去才能看到详情
因此需要获取每个房源的详情页面的URL
3. 观察某一房源的详细信息,这里我们提取“标题、地址、价格、房东名字、性别”等
使用BeautifulSoup实现
1 """ 2 典型的分页型网站——小猪短租 3 使用Beautifulsoup解析网页,并对比时间效率 4 5 """ 6 7 import requests 8 from bs4 import BeautifulSoup as bs 9 import time 10 11 headers = { 12 'User-Agent':'User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 13 } 14 15 #--Beautifulsoup-- 16 17 """获取每一个房源的网址,参数是分页url""" 18 def get_link(url): 19 html_data = requests.get(url, headers = headers) 20 soup = bs(html_data.text, 'lxml')#bs4推荐使用的的解析库 21 #print(soup.prettify()) #标准化输出url中的源代码(有可能跟网页查看中的不一致,网页中有可能标签书写不规范)以此为基础抓取,如果抓取失败,用此命令查看源代码 22 links = soup.select('#page_list > ul > li > a')#注意循环点!!!直接粘贴过来的是“#page_list > ul > li:nth-child(1) > a > img”,需要去掉:nth-child(1),注意每个标签前后有空格 23 #print(links) 24 for link in links: 25 link = link.get('href') 26 #print(link) 27 get_info(link) 28 29 """判断房东性别""" 30 def sex_is(member): 31 if member == 'member_ico': 32 return "男" 33 else: 34 return "女" 35 36 """获取每一个房源的详细信息,参数url是每个房源的网址""" 37 def get_info(url): 38 html_data = requests.get(url, headers = headers) 39 soup = bs(html_data.text, 'lxml')#bs4推荐使用的的解析库 40 # print(soup.prettify()) #标准化输出url中的源代码(有可能跟网页查看中的不一致,网页中有可能标签书写不规范)以此为基础抓取,如果抓取失败,用此命令查看源代码 41 title = soup.select('div.wrap.clearfix.con_bg > div.con_l > div.pho_info > h4 > em')[0].string 42 # 用网页copy过来的全部是“body > div.wrap.clearfix.con_bg > div.con_l > div.pho_info > h4 > em”,但是使用这个爬不出来数据(我也不知道why),把body去掉或者用下面最简短的方式(只使用最近的且唯一的div) 43 # title = soup.select('div.pho_info > h4 > em ') 44 # 查询结果title格式是一维列表,需要继续提取列表元素(一般就是[0]),列表元素是前后有标签需要继续提取标签内容,使用get_text()或者string 45 46 address = soup.select('div.wrap.clearfix.con_bg > div.con_l > div.pho_info > p > span')[0].string.strip() 47 price = soup.select('#pricePart > div.day_l > span')[0].string.strip() # div中的id=pricePart是唯一性的,因此不用写前面的div 48 name = soup.select('#floatRightBox > div.js_box.clearfix > div.w_240 > h6 > a')[0].string.strip() 49 img = soup.select('#floatRightBox > div.js_box.clearfix > div.member_pic > a > img')[0].get('src').strip() # 获取标签的属性值 50 sex = sex_is(soup.select('#floatRightBox > div.js_box.clearfix > div.member_pic > div')[0].get('class')[0].strip()) # 获取标签的属性值 51 52 #将详细数据整理成字典格式 53 data = { 54 '标题':title, 55 '地址':address, 56 '价格':price, 57 '房东姓名':name, 58 '房东性别':sex, 59 '房东头像':img 60 } 61 print(data) 62 63 64 """程序主入口""" 65 if __name__=='__main__': 66 start = time.time() 67 for number in range(1,4): 68 url = 'http://bj.xiaozhu.com/search-duanzufang-p{}-0/'.format(number) #构造分页url(不是房源详情的url) 69 get_link(url) 70 time.sleep(5) 71 end = time.time() 72 print('运行时长:',end-start)
使用Xpath实现
1 """ 2 典型的分页型网站——小猪短租 3 使用Xpath解析网页,并对比时间效率 4 """ 5 6 import requests 7 from lxml import etree 8 import time 9 10 headers = { 11 'User-Agent':'User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 12 } 13 14 #--Xpath-- 15 16 """获取每一个房源的网址,参数是分页url""" 17 def get_link(url): 18 html_data = requests.get(url, headers=headers) 19 selector = etree.HTML(html_data.text) 20 infos = selector.xpath('//*[@id="page_list"]/ul/li') 21 for info in infos: 22 link = info.xpath('a[1]/@href')[0].strip()#获取a标签中的href使用@,注意写法 23 #link = link.get('href') 24 #print(link) 25 get_info(link) 26 27 """判断房东性别""" 28 def sex_is(member): 29 if member == 'member_ico': 30 return "男" 31 else: 32 return "女" 33 34 """#获取每一个房源的详细信息,参数url是每个房源的网址""" 35 def get_info(url): 36 html_data = requests.get(url, headers=headers) 37 selector = etree.HTML(html_data.text) 38 # title = selector.xpath('//div[3]/div[1]/div[1]/h4/em')#直接使用copyxpath的结果为空,原因未知,address字段同样情况 39 title = selector.xpath('//div[@class="wrap clearfix con_bg"]/div[1]/div[1]/h4/em/text()')[0].strip() 40 # title = selector.xpath('//div[@class="pho_info"]/h4/em/text()')[0].strip() 41 address = selector.xpath('//div[@class="pho_info"]/p/span/text()')[0].strip() 42 price = selector.xpath('//*[@id="pricePart"]/div[1]/span/text()')[0].strip() 43 #name = selector.xpath('//*[@id="floatRightBox"]/div[3]/div[2]/h6/a/@title')[0].strip()#此段是直接copy xpath的,某些房源会报错,因为有些房东认证了“超棒房东”,会多一行div 44 name = selector.xpath('//*[@id="floatRightBox"]/div[3]/div[@class="w_240"]/h6/a/@title')[0].strip() 45 #img = selector.xpath('//*[@id="floatRightBox"]/div[3]/div[1]/a/img/@src')[0].strip()#原因同name 46 img = selector.xpath('//*[@id="floatRightBox"]/div[3]/div[@class="member_pic"]/a/img/@src')[0].strip() 47 48 sex = sex_is(selector.xpath('//*[@id="floatRightBox"]/div[3]/div[1]/div/@class')[0].strip()) 49 #将详细数据整理成字典格式 50 data = { 51 '标题':title, 52 '地址':address, 53 '价格':price, 54 '房东姓名':name, 55 '房东性别':sex, 56 '房东头像':img 57 } 58 print(data) 59 60 61 """程序主入口""" 62 if __name__=='__main__': 63 start = time.time() 64 for number in range(1,4): 65 url = 'http://bj.xiaozhu.com/search-duanzufang-p{}-0/'.format(number) #构造分页url(不是房源详情的url) 66 get_link(url) 67 time.sleep(5) 68 end = time.time() 69 print('运行时长:',end-start)
对比时间效率
爬取1-3页数据,每页延时5s
BeautifulSoup用时27.9475s
XPath用时24.0693s
综上所述
XPath用时更短一些,并且XPath写法更简洁。对比而言,更推荐使用XPath进行网页解析。
值得注意的是,copy XPath的方法虽然好用,但是某些情况有可能抓取失败,比如本例中的title、name和img,此时需要手写(可以尝试明确class和id的写法提高抓取效率)