15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > 网络爬虫系列 静态网页与动态网页的简单实战

网络爬虫系列 静态网页与动态网页的简单实战

时间:2023-10-12 10:48:01 | 来源:网站运营

时间:2023-10-12 10:48:01 来源:网站运营

网络爬虫系列 静态网页与动态网页的简单实战:

0.准备工作

本文将介绍以下三种爬虫工具的简单使用方法,也附上官网文档的地址,便于大家日后深入学习。

安装Requests

conda install requests安装BeautifulSoup

conda install bs4 安装Selenium

conda install selenium

1.简单的爬虫实例

1.1静态网页的爬取

单页爬取

下面我们来爬取中关村ZOL网站的手机数据,如图中绿框所示。该网页地址是http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_1.html

import requestsfrom bs4 import BeautifulSoupimport numpy as npimport pandas as pd使用.get()函数获得网站资源,显然这里使用了http访问方法中的get方法。服务器返回代码200,表示http请求-响应成功,我们已经获得网页数据。

url = 'http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_1.html'data = requests.get(url, timeout=1) # timeout设置等待时间,超时未收到响应的话则返回连接失败data


<Response [200]>requests会根据获得的数据来推测网页的字符编码,但这未必准确。

data.encoding # 查看网页编码


'GBK'


#data.encoding = 'UTF-8' #如果通过.text得到的字符串出现乱码,则需要用此行代码重新编码。正确的网页字符编码可以在HTML的head里查看。d_text = data.textd_text[:2000]


'<!DOCTYPE html>/r/n<html>/r/n<head>/r/n<meta charset="GBK" />/n/t<title>【最热门手机大全】最热门手机报价及图片大全-ZOL中关村在线</title>/n/t<meta name="keywords" content="最热门手机,最热门手机报价,最热门手机价格,手机大全,手机最新报价" />/n/t<meta name="description" content="ZOL中关村在线提供最热门手机最新价格及经销商报价,包括最热门手机大全,最热门手机参数,最热门手机评测,最热门手机图片,最热门手机论坛等详细内容,为您购买最热门手机提供全面参考" />/n<meta http-equiv="Cache-Control" content="no-siteapp"/>/n/t<meta http-equiv="Cache-Control" content="no-transform"/>/n/t<meta name="applicable-device" content="pc">/n/t<meta name="referrer" content="unsafe-url">/n/t<meta http-equiv="mobile-agent" content="format=xhtml; url=https://wap.zol.com.cn/list/57.html?j=simple"/>/n<meta http-equiv="mobile-agent" content="format=html5; url=https://wap.zol.com.cn/list/57.html"/>/n<meta name="mobile-agent" content="format=wml;url=https://wap.zol.com.cn/list/57.html"/>/n<meta name="mobile-agent" content="format=xhtml;url=https://wap.zol.com.cn/list/57.html"/>/n<link rel="alternate" media="only screen and(max-width:640px)" href="https://wap.zol.com.cn/list/57.html"/>/n<script>(function(){var fromVal=document.location.href.indexOf("from=jinritoutiao") > -1 ? "?from=jinritoutiao" : "";var a=1,d="https://wap.zol.com.cn/list/57.html"+fromVal,b=document.cookie,c=document.referrer;b&&b.match(/mobile_agent_global_dapter=([^;$]+)/)&&(a=b.match(/mobile_agent_global_dapter=([^;$]+)/)[1]);if(1===a&&""!==d&&(/AppleWebKit.*Mobile/i.test(navigator.userAgent)||/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE|TAH-AN00m/.test(navigator.userAgent))&&0>window.location.href.indexOf("?via=")){a=new Date;c=""===c?"none":-1<c.indexOf("?")?c+"&pcjump=1":c+"?pcjump=1";b&&(a.setDate(a.getDate()+1),document.cookie="PC2MRealRef="+escape(c)+";expires="+a.toGMTString()+/r/n"; domain=.zol.com.cn; path=/");try{/Android|Windows Phone|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)&&(window.location.href=d)}catch(e){}}})();</script>/n<script type="text/javascript" src="//icon.zol-img.com.cn/swfobject.'d_text里的数据只是字符串格式,BeautifulSoup不能直接解析。首先转换成BeautifulSoup对象,它是一个复杂的树形结构,就像开发者工具里看到的层次分明的HTML。

soup = BeautifulSoup(d_text)type(soup)


bs4.BeautifulSoup下面开始提取我们需要的数据。可用.find(), .find_all(), .select()。以.select()为例,它是一个CSS选择器,根据HTML的标签、属性、层级关系来定位我们需要的数据。
我们可以在开发者工具里面找出各个标签之间的层级关系,相当于“地址”。这个“地址”可长可短,只要保证这个地址能够唯一地定位到特定的数据就可以了。
例如,手机信息的文本在标签a里,它的上一级是标签h3,再上一级是li,再上一级是ul(且标签class=clearfix),以此类推。下面的代码使用了6个标签来定位,读者可以尝试只写“li > h3 > a” 这3个标签,事实上会得到同样的结果。

phone_name = soup.select('div.content > div.pic-mode-box > ul.clearfix > li > h3 > a') # 根据HTML的层次结构定位所需要的数据phone_name[:5]


[<a href="/cell_phone/index1345834.shtml" target="_blank" title="vivo X60 Pro+(8GB/128GB/全网通/5G版)微云台双主摄,骁龙888,蔡司联合影像系统">vivo X60 Pro+(8GB/128GB/全网通/5G版) <span>微云台双主摄,骁龙888,蔡司联合影像系统</span></a>, <a href="/cell_phone/index1337045.shtml" target="_blank" title="OPPO Reno5 Pro(8GB/128GB/全网通/5G版)闪电启动,星钻光芒设计,6400万水光人像四摄">OPPO Reno5 Pro(8GB/128GB/全网通/5G版) <span>闪电启动,星钻光芒设计,6400万水光人像四摄</span></a>, <a href="/cell_phone/index1337287.shtml" target="_blank" title="华为Mate40 Pro(8GB/256GB/全网通/5G版/玻璃版)麒麟9000,88°超曲环幕屏,66W快充,50W无线快充,IP68级防水防尘,3D人脸识别">华为Mate40 Pro(8GB/256GB/全网通/5G版/玻璃版) <span>麒麟9000,88°超曲环幕屏,66W快充,50W无线快充,IP68级防水防尘,3D人脸识别</span></a>, <a href="/cell_phone/index1345628.shtml" target="_blank" title="三星Galaxy S21 Ultra(12GB/256GB/全网通/5G版)骁龙888,1.08亿像素,120Hz护目屏,支持Spen">三星Galaxy S21 Ultra(12GB/256GB/全网通/5G版) <span>骁龙888,1.08亿像素,120Hz护目屏,支持Spen</span></a>, <a href="/cell_phone/index1330551.shtml" target="_blank" title="三星Galaxy Note 20 Ultra(12GB/256GB/全网通/5G版)S Pen,三星笔记,120Hz自适应屏幕,专业视频拍摄">三星Galaxy Note 20 Ultra(12GB/256GB/全网通/5G版) <span>S Pen,三星笔记,120Hz自适应屏幕,专业视频拍摄</span></a>]代码至此,我们已经很接近得到最终的数据了。从上述的结果来看,手机信息就藏在a标签里面,下面使用.get_text()函数提取出来。

for i in phone_name[:5]: name = i.get_text() # .get.text()函数可以获取标签里的文本 print(name)


vivo X60 Pro+8GB/128GB/全网通/5G版 微云台双主摄骁龙888蔡司联合影像系统OPPO Reno5 Pro8GB/128GB/全网通/5G版 闪电启动星钻光芒设计6400万水光人像四摄华为Mate40 Pro8GB/256GB/全网通/5G版/玻璃版 麒麟900088°超曲环幕屏66W快充50W无线快充IP68级防水防尘3D人脸识别三星Galaxy S21 Ultra12GB/256GB/全网通/5G版 骁龙8881.08亿像素120Hz护目屏支持Spen三星Galaxy Note 20 Ultra12GB/256GB/全网通/5G版 S Pen三星笔记120Hz自适应屏幕专业视频拍摄我们已经知道如何利用.get_text()函数可以获得数据,所以到了爬虫的最后一步:存储数据。这一步我们使用pandas第三方库。

phone_info = pd.DataFrame(columns=['name'])phone_info['name'] = [i.get_text() for i in phone_name]phone_info.head()


name0 vivo X60 Pro+(8GB/128GB/全网通/5G版) 微云台双主摄,骁龙888,...1 OPPO Reno5 Pro(8GB/128GB/全网通/5G版) 闪电启动,星钻光芒设计,...2 华为Mate40 Pro(8GB/256GB/全网通/5G版/玻璃版) 麒麟9000,88°...3 三星Galaxy S21 Ultra(12GB/256GB/全网通/5G版) 骁龙888,1...4 三星Galaxy Note 20 Ultra(12GB/256GB/全网通/5G版) S P...以csv格式保存数据至当前目录。此处注意编码问题。

phone_info.to_csv('phone_info.csv', encoding='utf_8_sig')以上是一个简单又完整的爬虫例子,后面的代码都是基于这个思路编写,大家读懂了上述内容的话,相信接下来的内容也能很快看懂。

多页爬取

利用url的变化规律

对比以下两个地址,我们发现不同页的地址的区别,就在于最后一个数字。
第一页:http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_1.html
第二页:http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_2.html
这里我们只需要在上面的代码外添加一个循环语句就可以实现多页采集了。

def multi_url(): phone_dataset = [] # 存储数据 for num in range(1, 3): # 改变地址的特定部分 u = f'http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_{num}.html' # 检查地址是否正确 try: data = requests.get(u, timeout=1) data.encoding # 理论上,若URL错误,则无法获得网页资源,从而无法进行encoding,程序会报错 except: print('已到达最后一页!') return phone_dataset d_text = data.text # 采集当前页面的数据 soup = BeautifulSoup(d_text) phone_name = soup.select('div.content > div.pic-mode-box > ul.clearfix > li > h3 > a') # 储存 for j in phone_name: phone_dataset.append(j.get_text()) return phone_datasetphone2 = multi_url()print(phone2[-3:])


['华为nova 7 SE(8GB/128GB/5G版/全网通) 麒麟820,6400万高清AI四摄,40W超级快充', '华为nova 5 Pro(8GB/128GB/全网通) 3200万超高清自拍,人像超级夜景', '荣耀30S(8GB/128GB/全网通/5G版) 5G双模,麒麟820,40W快充']

利用“下一页”按钮实现

我们点击“下一页”按钮会跳转到新一页,是因为这个按钮包含一个超链接,即下一页的URL。无论是手机信息还是按钮,都是HTML的一部分,所以利用BeautifulSoup可以提取出下一页的URL。
此处需要注意,下一页按钮里的URL并不完整,需要在它的前面补上http://detail.zol.com.cn/

def multi_next_page(): phone_dataset = [] # 存储数据 # 采集第一页数据 data = requests.get('http://detail.zol.com.cn/cell_phone_index/subcate57_0_list_1_0_1_2_0_1.html').text soup = BeautifulSoup(data) phone_name = soup.select('div.content > div.pic-mode-box > ul.clearfix > li > h3 > a') for i in phone_name: phone_dataset.append(i.get_text()) # 开始多页循环 base_url = 'http://detail.zol.com.cn/' num = 1 while num < 2: try: p = soup.select('a.next') # 定位到“下一页”按钮 page = p[0].get('href') # 通过.get('herf')来获得下一页的部分地址 num += 1 print(f'第{num}页采集ing...') except: print('采集完成!') return phone_dataset url = base_url + str(page) # 合并成完整的地址 # 采集数据 data = requests.get(url).text soup = BeautifulSoup(data) phone_name = soup.select('div.content > div.pic-mode-box > ul.clearfix > li > h3 > a') for i in phone_name: phone_dataset.append(i.get_text()) return phone_datasetphone3 = multi_next_page()print(phone3[-3:])


['华为nova 7 SE(8GB/128GB/5G版/全网通) 麒麟820,6400万高清AI四摄,40W超级快充', '华为nova 5 Pro(8GB/128GB/全网通) 3200万超高清自拍,人像超级夜景', '荣耀30S(8GB/128GB/全网通/5G版) 5G双模,麒麟820,40W快充']

1.2动态网页

接下里,我们将尝试访问网易严选,爬取飞天茅台的评价内容。附上茅台商品的介绍页:http://you.163.com/item/detail?id=3995885&_stat_area=mod_16_item_15&_stat_id=1005002&_stat_referer=itemList

使用requests方法

虽然我们无法直接从动态网页的源代码里找到需要的信息,但是,既然这些内容能够加载到浏览器里,那么我们必然接收到了某些数据,我们可以在开发者工具里找它们的藏身之处。

注意
开发者工具的Network功能里的内容,是根据时间先后的顺序显示的,以进入“Network”的那一刻为0时刻,而不是从进入网页的时刻开始计算;其次,Network里的内容也根据用户的操作而加载,这契合动态网页的特点。有的读者在初次使用Network功能时会看到里面空白一片,请刷新一下网页,相信你马上会理解这个模块的运行逻辑。

我们在开发者工具里找一条非常复杂的URL,疑似“评论内容”的真实地址,并通过在“Preview”里验证了该URL的内容,正是我们要爬取的评论。

在content处发现评价内容
把找到的URL交给requests,进行HTTP访问。

注意到,我们找到的Request URL,与茅台的原始地址是完全不一样的。
url = r'http://you.163.com/xhr/comment/listByItemByTag.json?__timestamp=1612421786209&itemId=3995885&tag=%E5%85%A8%E9%83%A8&size=20&page=1&orderBy=0&oldItemTag=%E5%85%A8%E9%83%A8&oldItemOrderBy=0&tagChanged=0'data = requests.get(url)d_text = data.textd_text[:2000]


'{"code":"200","data":{"pagination":{"page":1,"size":20,"totalPage":1288,"total":25748,"lastPage":false},"commentList":[{"skuInfo":["规格:1瓶"],"frontUserName":"小****","frontUserAvatar":"https://yanxuan.nosdn.127.net/4719d50913c28fac5aa575ba6f21fe20","content":"物流非常快,质量非常好,客服态度非常好,相信我自己还能再中一次!","createTime":1603867171787,"picList":["https://yanxuan.nosdn.127.net/05b30e92fd11ddef6decdded5c674253.jpg","https://yanxuan.nosdn.127.net/110e362866760ce9b0d7ccdee76f4bfe.jpg"],"commentReplyVO":null,"memberLevel":5,"appendCommentVO":{"id":143233162,"createTime":1603867470466,"content":"很有品质保证,买买买!!!","picList":["https://yanxuan.nosdn.127.net/8e63dc16f7be996cafbb8094fd039f1a.jpg","https://yanxuan.nosdn.127.net/66825d8d503f08074fa1ef7fd88a14f3.jpg"],"commentReplyVO":null},"star":5,"itemId":3995885},{"skuInfo":["规格:1瓶"],"frontUserName":"用****8","frontUserAvatar":"https://yanxuan.nosdn.127.net/9e6dadfc9eb0954061797dfd88f13980.jpg","content":"终于抢到一瓶,感谢网易严选!希望能再给我中一瓶!","createTime":1605188815733,"picList":["https://yanxuan.nosdn.127.net/8bfe48109701139745ac8c6018bf38f5.jpg"],"commentReplyVO":null,"memberLevel":4,"appendCommentVO":null,"star":5,"itemId":3995885},{"skuInfo":["规格:1瓶"],"frontUserName":"r****0","frontUserAvatar":null,"content":"终于让我抢到一瓶,太好了,抢不到只能从黄牛手里拿了","createTime":1606895108114,"picList":["https://yanxuan.nosdn.127.net/f94f2a8d0689622d5391aa7b29371522.jpg"],"commentReplyVO":null,"memberLevel":5,"appendCommentVO":null,"star":5,"itemId":3995885},{"skuInfo":["规格:1瓶"],"frontUserName":"1****3","frontUserAvatar":"http://yanxuan.nosdn.127.net/bb31a487ad26923bcf115f896e789ebf","content":"速度很快,酒不错,包装很到位,很好,网易严选,很好,产地直接发货,厉害了,支持","createTime":1603806876726,"picList":["https://yanxuan.nosdn.127.net/0dfc65a5b6b475175600f9f7908483ef.jpg","https://yanxuan.nosdn.127.net/d8d638707f3541da4205b9a4af4ea072.jpg","https://yanxuan.nosdn.127.net/f71bbb359b0f59bd28c96792836e5869.jpg","https://yanxuan.nosdn.127.net/e73fb3856d31edcd2f8c25ffe9465427.jpg","https://yanxuan.nosdn.127.net/97266996534f'


仔细看上述的输出结果,并不是HTML,而是一种名为json的数据。利用Python自带的json库将其转换格式。

import jsonjson_data = json.loads(d_text)type(json_data)


dict这里的json数据存在复杂的字典与列表嵌套(大家可以自行print出来观察),肉眼不容易看清楚嵌套关系,但开发者工具提供了良好的可视化(Network——Preview),正如上一幅图片所示。根据其中的嵌套逻辑,我们先找到了第一条评论。

comment_list = json_data['data']['commentList'][0]['content']comment_list
从上一幅图片看到,data隔离有一个大括号 { ,因此这一层是字典;而 0 隔壁有一个中括号 [ ,所以这层是列表。以此类推。
'物流非常快,质量非常好,客服态度非常好,相信我自己还能再中一次!'在开发者工具里对比观察第一、第二条评论的索引,我们发现'data''commentList''content'这三个索引值是固定不变的,只有0需要递增到1,因此我们只需要运用循环语句,改变第三个索引值,就能获得其余的评价内容。同时注意单页的评价数,下面提供两种方法,推荐使用第二条语句。

len(json_data['data']['commentList']) # 使用函数计算本页评价的数量json_data['data']['pagination']['size'] # json数据也交代了该页的评价数,可以直接索引获取


comment_list = [json_data['data']['commentList'][i]['content'] for i in range(20)]comment_list


['物流非常快,质量非常好,客服态度非常好,相信我自己还能再中一次!', '终于抢到一瓶,感谢网易严选!希望能再给我中一瓶!', '终于让我抢到一瓶,太好了,抢不到只能从黄牛手里拿了', '速度很快,酒不错,包装很到位,很好,网易严选,很好,产地直接发货,厉害了,支持', '好不容易抢到一瓶,真心不容易。但是也非常幸运吧。网易几年的老用户了,东西都不错,价格也便宜。没啥理由不选网易严选的东西。以后还会一如既往地选择严选。', '几个平台只有网易抢到了,包装完美,有严选的溯源码是正品,感谢三石!!再接再厉再来一瓶!!', '严选还有专门的溯源标签,点赞,飞天真香呀,顺丰超快,开森^_^', '贴严选标签了,看着很好,舍不得拆开看里面的酒,应该没问题。希望还能再买到', '物流很快,隔天就到了,酒完美无瑕疵,还会回购的', '酒收到了、包装完美、货真价实。感谢网易这么好的购物平台,晚上就和朋友们喝了去', '第1次喝到平价的茅台,平常喝的都是3000多一瓶。迫不及待与好友共饮,大家合作都比较愉快。好酒!', '努力了几天抢到了,这么多年老用户了不让我买到,我会心寒的,不错,速度很快,包装很妥帖,有海绵垫瓶盖也有海绵垫,防护工作做的很好,家里有几样东西常年用严选的,加把劲再让我抢一瓶,这才对得起我的支持 ', '包装太好了,太精美了,网易云县良心良心。以后购物就在网易严选呐。', '完美,很开心能抢到,感谢平台,平台的服务也很好', '不错不错!几天努力终于抢到了了,快递速度很快,产品保护周全,安全收到了,各方面都很好,好评!', '网易严选非常靠谱,值得信赖!多年的客户了,酱香经典、茅台最醇!非常不错,留着过年和家人一起喝,感谢网易严选!', '发货速度非常快,第二天就到了,验看了一下,包装很好,是正品,值得购买。', '非常漂亮的茅台酒,网易严选必出精品,超级喜欢,物流也非常不错,还要继续购买', '包装很好,酒品很好。非常完美', '未填写评价内容']

使用selenium

使用requests爬取动态网页有一定的局限性,比如URL不好找、URL动态变化且加密等情况。而利用selenium模拟真人操作,可以非常直观地爬取数据。但是它也有缺点:爬虫效率易受电脑性能与网速的影响。

from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport timeselenium依赖浏览器程序而运行,因此第一步就需要给它定义一个浏览器。运行本行代码会弹出浏览器窗口。文件夹里提供一个微型的88.0版本谷歌浏览器,当然大家也可以用自己喜欢的浏览器。

driver = webdriver.Chrome(executable_path='./chromedriver.exe')driver.get(r'http://you.163.com/item/detail?id=3995885&_stat_area=mod_16_item_16&_stat_id=1005002&_stat_referer=itemList')time.sleep(2) # 相当于给代码运行添加一个空白过程,便于等待页面加载商品的首页不会出现评论,需要点击“评论”按钮,等待评论内容加载后才能爬取。这就需要让selenium模拟真人进行鼠标操作。

button = driver.find_element_by_css_selector('li.item-1') # 通过CSS选择器定位“评论”按钮action = ActionChains(driver).move_to_element(button) # 模拟将鼠标悬停到按钮上action.click(button).perform() # .click()即点击,perform()表示执行上述所有动作链time.sleep(1)将页面拉到最底部,从而加载本页所有评论。

driver.execute_script("var q=document.documentElement.scrollTop=10000")下面解析HTML的操作与BeautifulSoup类似,selenium也可以用CSS选择器定位特定数据,然后用.text获得文本。

comment_list = driver.find_elements_by_css_selector('div.content.f-breakall')comment_list[:5]


[<selenium.webdriver.remote.webelement.WebElement (session="33efbd2ce88b7c5d03394f6eaa65503c", element="6d89b995-76ef-4ffd-9b74-80a5a8e68873")>, <selenium.webdriver.remote.webelement.WebElement (session="33efbd2ce88b7c5d03394f6eaa65503c", element="44819238-ae3d-4212-b452-10eae73a6c27")>, <selenium.webdriver.remote.webelement.WebElement (session="33efbd2ce88b7c5d03394f6eaa65503c", element="df90dd8f-41a6-471f-9cde-ccf7d48cafc5")>, <selenium.webdriver.remote.webelement.WebElement (session="33efbd2ce88b7c5d03394f6eaa65503c", element="f3469893-c40e-4cfd-822f-749b86054382")>, <selenium.webdriver.remote.webelement.WebElement (session="33efbd2ce88b7c5d03394f6eaa65503c", element="58b21810-515a-4cde-8786-408d8ce73b49")>]


comment_text = [i.text for i in comment_list]comment_text[:5]


['物流非常快,质量非常好,客服态度非常好,相信我自己还能再中一次!', '[追评] 很有品质保证,买买买!!!', '终于抢到一瓶,感谢网易严选!希望能再给我中一瓶!', '终于让我抢到一瓶,太好了,抢不到只能从黄牛手里拿了', '速度很快,酒不错,包装很到位,很好,网易严选,很好,产地直接发货,厉害了,支持']

2.小结

网络爬虫技术入门快速但不止于此,网页功能繁多、网页设计形式各式各样,requests、BeautifulSoup、Selenium还有许多功能,帮助我们应对不同的网页,大家一定要在实践中学习。

关键词:简单,实战,动态,静态,爬虫,网络,系列

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭