爬虫思路分析:
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的写法提高抓取效率)