爬虫心得
爬虫的最终目的是通过程序模拟用户上网,爬取目标网站的相关数据。那么,就需要有python数据结构的相关知识,主要涉及序列、元组和字典。
-
序列 序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。 list1 = ['physics', 'chemistry', 1997, 2000]
-
元组 tup1 = ('physics', 'chemistry', 1997, 2000)
-
字典 dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Name']
str(dict)
GET请求目标网站
-
实现步骤: 第一步:获取目标网站的url 第二步:通过requests库发送get请求 第三步:设置参数用来接收返回的网站 第四步:通过xpath解析数据 -
案例分析 import requests
from lxml import etree
url="http://www.sxjybk.com/gdjy.htm"
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
}
resp=requests.get(url,headers=headers);
resp.encoding=resp.apparent_encoding
html=etree.HTML(resp.text);
_pageNum=html.xpath("/html/body/div[3]/div[3]/div/span/span[9]/a/text()")
pageNum="".join(_pageNum);
currentPage=int(pageNum)
while currentPage>0:
page_url = "http://www.sxjybk.com/gdjy/"+str(currentPage)+".htm"
_resp = requests.get(page_url, headers=headers);
_resp.encoding = _resp.apparent_encoding
html = etree.HTML(_resp.text);
a_list=" ".join(html.xpath("/html/body/div[3]/div[3]/ul/li/a[2]/@href"))
news_list=a_list.replace("..","http://www.sxjybk.com/").split()
for href in news_list:
resp = requests.get(href, headers=headers);
resp.encoding = resp.apparent_encoding
item_html = etree.HTML(resp.text)
content = "".join(item_html.xpath("//html/body/div[3]/form/div[3]/div[1]/div/p/text()"))
title = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/span[2]/text()"))
source = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/div[1]/span[1]/text()")).strip().replace("来源:"," ")
date_time = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/div[1]/span[3]/text()")).replace('年', '-').replace('月', '-').replace('日', '')
if content!="":
edu_info = {
"title": title,
"date": date_time,
"source": source,
"content": content
}
else:
content_02="".join(item_html.xpath("/html/body/div[3]/form/div[3]/div[1]/div/div/p/text()"))
edu_info = {
"title": title,
"date": date_time,
"source": source,
"content": content_02
}
print(edu_info)
currentPage=currentPage-1
resp.close();
POST请求目标网站
如果通过xpath解析,返回的是空列表,然后通过谷歌浏览器开发者模式,在response的源代码中搜索目标内容,如果没搜到,并且再次发送请求网站没刷新,很大程度上,该页面是通过ajax发出异步请求将返回的数据渲染在页面上的。
-
实现步骤 第一步:获取目标网站的url 第二步:通过requests库发送get请求 第三步:设置参数用来接收返回的网站 第四步:通过xpath解析数据 -
案例分析: import requests
from lxml import etree
import re
url = "https://www.shxbe.com/front/node/4/nodeData"
params = {
'nodeId': 4,
'pageSize': 9,
'curPage': 1
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
}
resp = requests.post(url, headers=headers, data=params);
resp.encoding = resp.apparent_encoding
html = etree.HTML(resp.text);
if resp.status_code == 200:
info = resp.json()
current_page = int(info["curPage"])
pageNum = int(info['totalPage'])
while current_page <= pageNum:
page_url = "https://www.shxbe.com/front/node/4/nodeData"
params = {
'nodeId': 4,
'pageSize': 9,
'curPage': current_page
}
_resp = requests.post(page_url, headers=headers, data=params);
_resp.encoding = _resp.apparent_encoding
html = etree.HTML(_resp.text);
if _resp.status_code == 200:
info = _resp.json()
id_list = info["list"]
for value in id_list:
href = "https://www.shxbe.com/front/node/recordInfor/" + str(value['id'])
resp = requests.get(href, headers=headers);
resp.encoding = resp.apparent_encoding
item_html = etree.HTML(resp.text)
title = "".join(item_html.xpath("/html/body/div[2]/div[2]/h1/text()"))
source = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[3]/p/i[1]/text()"))
date = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[1]/div[1]/i/text()"))
_content = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[2]/p/span/text()"))
content = re.sub("\s", '', _content);
if content != "":
edu_info = {
'title': title,
'source': source,
'date': date,
'content': content
}
print(edu_info)
current_page = current_page + 1
resp.close()
几个重要的方法
-
字符串相关
方法 | 说明 |
---|
“”.join(param1) | 将param1转字符串 | str(obj) | 返回一个对象的string格式 | strip() | 去除首尾空格 |
-
re相关
-
正则表达式 量词 控制前面的元字符出现的次数
量词 | 说明 |
---|
* | 重复零次或多次 | + | 重复1次或多次 | ? | 重复0次或一次 | {n} | 重复n次 | .* | 贪婪匹配 | .*? | 惰性匹配 |
常用元字符
模式 | 描述 |
---|
^ | 匹配字符串的开头 | $ | 匹配字符串的末尾。 | . | 匹配换行符以外的任意字符 | […] | 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’ | [^…] | 不在[]中的字符 | \w | 匹配字母、数字、下划线 | \s | 匹配任意空白字符,等价于 [ \t\n\r\f]。 | \d | 匹配任意数字,等价于 [0-9] |
-
方法 引入re库:import re
方法名 | 说明 | 举例 |
---|
sub(pattern, repl, string, count=0, flags=0) | 替换字符串中的匹配项 | content = re.sub("\s", ‘’, _content);替换空白字符 | findall(string[, pos[, endpos]]) | 返回正则表达式所匹配的所有子串 列表 | source = re.findall(r"文章来源:(.+?) ", _source) |
tips
一、伪装成正常访问 审查元素 Networks--Headers---User-Agent
headers={User-Agent:" "}
requests.get(url,headers=headers)
二、爬取最后一步 resp.close()
三、数据解析
(1)re解析 正则表达式 re模块
(2)bs4解析
(3)xpath解析
安装lxml pip install lxml
匹配规则:
/表示层级关系,第一个/是根节点
text()取标签内容
//后代
*任意的节点,通配符
页面复杂时,结合浏览器审查元素 copy xpath路径
四、请求参数过长,重新封装参数
Network-->Headers-->Query String Parameters (保存在params)
url="https://Www.baidu.com"
params={
"name":"pinkhub"
}
等价于url="https://www.baidu.com/?name=pinkhub"
安装requests插件 pip install requests
换源加速 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
五、注意点
1.如果xpath路径中存在tbody,要删掉tbody
2.发出请求没返回内容
(1)UA伪装
(2)反爬机制
3.乱码问题 windows系统电脑默认是gbk,需添加encoding='utf-8'
4.robots.txt协议 规范爬虫 网址/robots.txt
|