什么是爬虫
爬虫就是程序,一个能获取互联网上的资源(文字、图片、音视频)数据的程序。
不用爬⾍, 打开浏览器, 输⼊百度的⽹址,就能在浏览器上看到百度的内容了。那换成爬⾍呢? 道理是⼀样的。只不过,是⽤代码来模拟⼀个浏览器, 然后同样的输⼊百度的⽹址。那么程序也能拿到百度的内容
爬虫合法吗
爬虫在法律上暂时是不被禁止的。但服务器上的数据有产权归属,如果网络爬虫获取数据后牟利将带来法律风险。小规模,数据量小,频率不高, 不窃取用户隐私的爬取是可以的,合法的
反爬与反反爬
反爬机制:网站可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取
反反爬策略:爬虫程序可以通过制定相关的策略或者技术手段,破解网站中具备的反爬机制,从而可以获取网站中相关的数据。
robots.txt协议:君子协议。规定了网站中哪些数据可以被爬虫爬取哪些数据不可以被爬取
requests请求库
- 安装
pip install requests
- 请求百度首页源代码
import requests# 这样运行的话就把百度首页的html提取出来了url = "https://www.baidu.com/"response = requests.get(url)response.encoding = "utf-8"print(response.text)
XPath解析库
- ⼤多数情况下, 我们并不需要整个⽹⻚的内容, 只是需要那么⼀⼩部分。所以我们要做数据解析和提取。常见的有:xpath解析、BeautifulSoup解析、正则表达式re解析
- XPath是⼀⻔在 XML ⽂档中查找信息的语⾔, XPath可⽤来在 XML⽂档中对元素和属性进⾏遍历,⽽我们熟知的HTML恰巧属于XML的⼀个⼦集,所以完全可以⽤xpath去查找html中的内容
- 在python中想要使⽤xpath,需要安装lxml模块:pip install lxml
- 基础用法:①将要解析的html内容构造出etree对象②使⽤etree对象的xpath()⽅法配合xpath表达式来完成对数据的提取
html = """Title - 百度
- ⾕歌
- 搜狗
- ⻜机
- ⼤炮
- ⽕⻋
李嘉诚胡辣汤"""from lxml import etreetree = etree.XML(html)result = tree.xpath("/html/body/ul/li/a/@href")print(result)result = tree.xpath("/html/body/ul/li")for li in result:print(li.xpath("./a/@href"))result = tree.xpath("/html/body/ol/li/a/@href")print(result)
BeautifulSoup解析库
- 安装库:pip intall bs4
<html lang="en"><head><meta charset="UTF-8" /><title>测试bs4</title></head><body><div><p>百里守约</p></div><div class="song"><p>李清照</p><p>王安石</p><p>苏轼</p><p>柳宗元</p><a href="http://www.song.com/" title="赵匡胤" target="_self"><span>this is span</span>宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a><a href="" class="du">总为浮云能蔽日,长安不见使人愁</a><img src="http://www.baidu.com/meinv.jpg" alt="" /></div><div class="tang"><ul><li><a href="百度一下,你就知道" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li><li><a href="网易" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li><li><a href="126网易免费邮--你的专业电子邮" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li><li><a href="home.sina.com" class="du">杜甫</a></li><li><a href="Awesome Coming Soon Widget Responsive Widget" class="du">杜牧</a></li><li><b>杜小月</b></li><li><i>度蜜月</i></li><li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li></ul></div></body></html>from bs4 import BeautifulSoup#本地的htmlfp = open(r"test.html","r",encoding="utf-8")soup = BeautifulSoup(fp,"lxml")print(soup)#返回这个网页的源代码print(soup.a)#返回第一个a标签的内容print(soup.div) #返回第一个div 的内容print(soup.find("div"))#返回第一个div 的内容print(soup.find("div",class_="song")) #返回class = "song" 的div的内容print(soup.find_all("a"))#返回所有a标签的内容print(soup.find("div",class_="song").a.get("href"))# 返回http://www.song.com/print(soup.find("div",class_="song").img.get("src"))#返回http://www.baidu.com/meinv.jpgprint(soup.find("div",class_="song").a.text) # 返回文本print(soup.select('.tang')) 返回class = "tang" 的div的内容print(soup.select(".tang > ul > li > a")[0].text) # 返回tang下的第一个标签的内容print(soup.select(".tang > ul > li > a")[0]['href']) # 返回tang下的第一个标签的链接
正则表达式
- 正则表达式是用来简洁表达一组字符串的表达式
import re# 将正则表达式编译成为⼀个正则表达式对象, 规则要匹配的是3个数字obj = re.compile(r'\d{3}')# 正则表达式对象调⽤search, 参数为待匹配的字符串ret = obj.search('abc123eeee')print(ret.group()) # 结果: 123
元字符:具有固定含义的特殊符号 常⽤元字符:
. 匹配除换⾏符以外的任意字符
\w 匹配字⺟或数字或下划线
\s 匹配任意的空⽩符 \d 匹配数字
\n 匹配⼀个换⾏符
\t 匹配⼀个制表符
^ 匹配字符串的开始 $ 匹配字符串的结尾
\W 匹配⾮字⺟或数字或下划线
\D 匹配⾮数字
\S 匹配⾮空⽩符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示⼀个组
[…] 匹配字符组中的字符
[^…] 匹配除了字符组中字符的所有字符
量词: 控制前⾯的元字符出现的次数
*重复零次或更多次
+重复⼀次或更多次
” />str: 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游戏啊reg: 玩⼉.*?游戏此时匹配的是: 玩⼉吃鸡游戏reg: 玩⼉.*游戏此时匹配的是: 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游戏str: <div>胡辣汤</div>reg: <.*>结果: <div>胡辣汤</div>str: <div>胡辣汤</div>reg: <.*?>结果:<div></div>str: <div>胡辣汤</div><span>饭团</span>reg: <div>.*?</div>结果:<div>胡辣汤</div>
- 案例:练习用正则表达式提取豆瓣电影top250的数据并保存
# 拿到页面源代码. requests# 通过re来提取想要的有效信息reimport requestsimport reimport csvurl = "https://movie.douban.com/top250"headers = {"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36"}resp = requests.get(url, headers=headers)page_content = resp.text# 解析数据obj = re.compile(r'
.*?.*?(?P.*?)' r'.*? r'class="rating_num" property="v:average">(?P.*?).*?' r'(?P.*?)人评价', re.S)# 开始匹配result = obj.finditer(page_content)f = open("data.csv", mode="w")csvwriter = csv.writer(f)for it in result:print(it.group("name"))print(it.group("score"))print(it.group("num"))print(it.group("year").strip())dic = it.groupdict()dic['year'] = dic['year'].strip()csvwriter.writerow(dic.values())f.close()print("over!").*?
(?P.*?) .*?<span 'cookies:处理需要登陆的网站
headers为HTTP协议中的请求头。⼀般存放⼀些和请求内容⽆关的数据。有时也会存放⼀些安全验证信息,比如常⻅的User-Agent,cookies等。通过requests发送的请求, 我们可以把请求头信息放在headers中。也可以单独进⾏存放, 最终由requests⾃动帮我们拼接成完整的http请求头
selenium
Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接调用浏览器,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器),可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏等
- 在下载好chromedriver以及安装好selenium模块后,可以执行下列代码并观察运行的过程
from selenium import webdriver # 如果driver没有添加到了环境变量,则需要将driver的绝对路径赋值给executable_path参数# driver = webdriver.Chrome(executable_path='driver的绝对路径')# 如果driver添加了环境变量则不需要设置executable_pathdriver = webdriver.Chrome()# 向一个url发起请求driver.get("https://www.baidu.com/")# 把网页保存为图片driver.save_screenshot("baidu.png")# 打印页面的标题print(driver.title) # 在百度搜索框中搜索'python'driver.find_element_by_id('kw').send_keys('python')# 点击'百度搜索'driver.find_element_by_id('su').click()# 退出模拟浏览器driver.quit()
- selenium工作原理:利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的)
- 在selenium中可以通过多种方式来定位标签,返回标签元素对象
find_element_by_id (返回一个元素)find_element(s)_by_class_name (根据类名获取元素列表)find_element(s)_by_name (根据标签的name属性值返回包含标签对象元素的列表)find_element(s)_by_xpath (返回一个包含元素的列表)find_element(s)_by_link_text (根据连接文本获取元素列表)find_element(s)_by_partial_link_text (根据链接包含的文本获取元素列表)find_element(s)_by_tag_name (根据标签名获取元素列表)find_element(s)_by_css_selector (根据css选择器来获取元素列表)
- selenium获取cookie:driver.get_cookies()返回列表,其中包含的是完整的cookie信息!不光有name、value,还有domain等cookie其他维度的信息。所以如果想要把获取的cookie信息和requests模块配合使用的话,需要转换为name、value作为键值对的cookie字典
# 获取当前标签页的全部cookie信息print(driver.get_cookies())# 把cookie转化为字典cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()}
- selenium控制浏览器执行js代码
import timefrom selenium import webdriverdriver = webdriver.Chrome()driver.get("http://www.itcast.cn/")time.sleep(1)js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句driver.execute_script(js) # 执行js的方法 跳转到最底部time.sleep(5)driver.quit()
scrapy框架
- Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架
- scrapy的架构如下图,图中中文是为了方便理解后加上去的。图中绿色线条的表示数据的传递。注意图中中间件的位置,决定了其作用。注意其中引擎的位置,所有的模块之前相互独立,只和引擎进行交互
- 爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
- 调度器把request–>引擎–>下载中间件—>下载器
- 下载器发送请求,获取response响应–>下载中间件—->引擎—>爬虫中间件—>爬虫
- 爬虫提取url地址,组装成request对象—->爬虫中间件—>引擎—>调度器,重复步骤2
- 爬虫提取数据—>引擎—>管道处理和保存数据
scrapy的三个内置对象
- request请求对象:由url method post_data headers等构成
- response响应对象:由url body status headers等构成
- item数据对象:本质是个字典
scrapy中每个模块的具体作用