关注我天天好文
重点梳理
- Scrapy框架的组件和数据处理流程。
- 爬取的目的(项目中哪些地方需要用到爬虫的数据)。
- 使用的工具(抓包、下载、清理、存储、分析、可视化)。
- 数据的来源(能够轻松的列举出10个网站)。
- 数据的构成(抓取的某个字段在项目中有什么用)。
- 反反爬措施(限速、请求头、Cookie池、代理池、Selenium WebDriver、RoboBrowser、TOR、OCR)。
- 数据的体量(最后抓取了多少数据,多少W条数据或多少个G的数据)。
- 后期数据处理(持久化、数据补全、归一化、格式化、转存、分类)。
内容
- 爬虫合法性
避免干扰到访问网站的正常运行
传播审查数据内容,如果涉及用户隐私、商业机密等要及时停止爬取和传播 - 使用场景分类
- 通用爬虫:抓去主要成分、一整张页面数据
- 聚焦爬虫:建立在通用爬虫基础上,抓取页面中特定的局部内容
- 增量式爬虫:检测网站数据更新,只抓取更新的数据
- 反爬机制
防止同行竞品爬取自家数据。 - 反反爬机制
尽可能爬到有用信息。 - robots.txt协议
君子协议,规定哪些可以被爬,哪些不可以被爬。url:xx.com/robots.txt
allow or disallow - 碎碎念
Chrome-chrono插件 copy redirection的path
下载到服务器上Wget -c path - UA检测:HTTP请求协议中请求头有个UA(User-Agent),门户网站的服务器会检测这个身份标识是否是正常的浏览器访问还是爬虫,爬虫大概率会拒绝,所以要做UA伪装
- 代码转换网站 转换成爬虫代码
- AJAX能够实现页面的局部请求和刷新
XHR中的都是AJAX的数据包
当抓链接中的数据未得到想要的数据时,很可能是因为这部分数据是AJAX拿过来的
importrequestsimportjsonif__name__='__main__':word=input()post_url='url'data={'kw':word}headers={'User-Agent':'Mozilla/5.0 (Macintsh; Inte Mac OS X 1_15_7)'}res=requests.post(url=post_url,data=data,headers=headers)dic_obj=res.json()#拿到json类型数据fp=open(f'./{word}.json','w',encoding='utf-8')json.dump(dic_obj,fp=fp,ensure_ascii=False)下载与批量下载
- 掌握request =掌握爬虫50%
importrequests#第三方库,没有下载的下载一下 pip install requests#爬虫下载图片res=requests.get("url")print(res.content)#二进制字节流#content-type为text/plain的也是用res.text获取print(res.text)#获取网页 字符串类型数据及html源码#写文件withopen("beauty.jpg","wb")asf:f.write(res.content)#批量下载短视频headers={'User-Agent':'Mozilla/5.0 (Macintsh; Inte Mac OS X 1_15_7)'}#UA伪装#get->params#post->dataparams={'k':'v'}res=requests.get("url/post/",params=params,headers=headers)print(res.json())#只拿想要的data=res.json().get(key)video_urls=[data.get("desc"),data.get('video').get('play_addr').get('url_list')foritemindata]fortitle,urlinvideo_urls:res=requests.get(url)withopen(f"./document/{title}.mp4","wb")asf:f.write(res.contnt)print('ok')- 数据解析分类
数据可以在标签之间或标签中的属性中找到。 - 正则
单字符:.除换行以外所有字符[]:[aoe][a-w]匹记集合中任意一个字符
\d ;数字 [6-9]
\D:非数字
\w :数字、字母、下划线、中文
\W:非\w
\s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
\S:非空白
数量修饰:*>=0次+>=1?:可有可无,0次或者1次
{m):固定m次 hello{3,}
{m,} :至少m次
{m,n}:m-n次
边界:
$:以某结尾
^:以某开头
分组:
(ab)
贪婪模式:.*
非贪婪(惰性)模式:.*?
re.I:忽略大小写re.M:多行匹配re.S:单行匹配re.sub(正则表达式,替换内容,字符串)
#获取一个页面中所有内容中的图片#观察得到是都放在div class="thumb"中的img中ex='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'re.findall(ex,page_text,re.S)#注意必须得是re.S- bs4
python中独有的解析方式
数据解析的原理都是类似的,定位到标签,提取标签中的内容
具体操作:实例化一个beautifulsoup对象,并将页面源码数据加载到该对象中,通过调用对象中的相关属性及方法得到数据,数据解析会用到lxml包pip install lxml
- bs4
web scraping
HTML parsing ->Beautiful Soup
Beautiful Soup object
attrs
tag.attrs
根据HTML tree可以得到Beautiful Soup object这种节点的child,parent,next_sibling
tag_child
tag_child.parent
frombs4importBeautifulSoup fp=open('./test.html','r',encoding='utf-8')soup=BeautifulSoup(fp,'html5lib')#第一种soup=BeautifulSoup(fp,'lxml')#第二种print(soup.a)#a标签 就是返回<a>....</a>整个 返回第一个a标签print(soup.find('div',class_='song'))#soup.find=soup.tagname#class_是标签的classname,也可以是id=,attr=..,name=table_row=soup.find_all(name='tr')#把所有被<tr>标签包含的元素都放入这个listtable_row[0].td#其<td>print(soup.select('.tang'))#拿到classname='tang'的 也可以是id 等选择器#返回是一个列表,只要符合都会捕获到#还可以用于层级选择器print(soup.select('.tang>ul>li>a')[0].text)#>表示连续的一个上下级层级print(soup.select('.tang>ul a')[0]['href'])#空格表示可以隔代的祖孙层级#.text or get_text()可以获取选中标签里及其包含标签中的所有文本#.string 只获取该标签下直系的文本内容,下面标签嵌套的不行importrequestsfrombs4importBeautifulSoup# Specify the URL of the webpage you want to scrapeurl='https://en.wikipedia.org/wiki/IBM'# Send an HTTP GET request to the webpageresponse=requests.get(url)base_url="https://api.example.com/data"params={"page":1,"per_page":10}response=requests.get(base_url,params=params)response=requests.post(url,data)response=requests.post((https://api.example.com/submit),data={(key):(value)})response=requests.put(url,data)data=response.json()# Store the HTML content in a variablehtml_content=response.text# Create a BeautifulSoup object to parse the HTMLsoup=BeautifulSoup(html_content,'html.parser')# Display a snippet of the HTML contentprint(html_content[:500])# Find all <a> tags (anchor tags) in the HTMLelements=soup.find_all(tag,attrs)links=soup.find_all('a')titles=soup.select((h1))#<h1>child_elements=parent_div.findChildren()sibling=element.find_next_sibling()parent=element.parent# Iterate through the list of links and print their textforthe linkinlinks:print(link.text)- xpath
最便捷最常用的一种解析方式。
实例化一个etree对象,且需要将被解析的页面源码加载到对象中,调用etree对象的xpath方法结合xpath表达式实现定位和数据解析。pip install lxml
- xpath
fromlxmlimportetree tree=etree.parse(filepath)#本地加载tree=etree.HTML('page_text')#接口res.text获取到的数据加载#xpath表达式 xpath('xpath表达式')obj=tree.xpath('/html/head/title')#返回的一个element对象obj_list=tree.xpath('/html//div')#//可跨越多个层次 返回一个listobj2=tree.xpath('//div[@class="song"]')#属性定位obj3=tree.xpath('/html//div[3]')#索引从1开始#取文本#/text()取直系文本内容 而不是其下元素包含的文本#//text()获取的是标签中所有文本内容 包括其下元素包含的文本text=tree.xpath('/html//div[3]/text()')[0]text=tree.xpath('//li[7]//text()')#取属性 /@arrt_name#局部解析e.xpath('./a')#./表示是e作为当前路径下面的a#处理中文乱码解决方案img_name=img_name.encode('iso-8859-1').decode('gbk')#或者res.encoding='utf-8'#逻辑运算符#或obj_list2=tree.xpath('/html/head/title | //li[7]')openpyxl库
读写操作excel文件(.xlsx格式)
pip install openpyxlimportopenpyxl#fileworkbook=openpyxl.load_workbook('name.xlsx')#sheetsheet=workbook['Sheet']#单元格value=sheet['A1'].value sheet['C2'].value='666'#saveworkbook.save('name.xlsx')#createworkbook=openpyxl.Workbook()sheet=workbook.active#获取默认工作表sheet.append([1,2,3,4,5,7,6,8,9])#写入一行数据foriinrange(100):#多行sheet.append([i,i+1,2,3,4,5,7,6,8,9])#saveworkbook.save('new_name.xlsx')实战:爬数据写入excel
检查->网络->创建一个请求->复制cURL
找一个网站
importrequestsimportopenpyxl cookies={...}headers={...}response=requests.get('url?r=0&count=10&categories=%70....',cookies=cookies,headers=headers,)#url中常有count=10,可修改成想获取的条数print(response.text)print(response.json())data=response.json().get("items")foritemindata:if(item.get('type')=='a'):title=item.get("title")count=item.get("rating").get("count")#save to excel#createworkbook=openpyxl.Workbook()sheet=workbook.active#获取默认工作表for...#多行写入data#saveworkbook.save('new_name.xlsx')