找到爬取目标
要想通过机器爬取数据,必须先知道数据在哪,通过什么样的方式获取数据。
一般先打开要爬取的网站,再通过审查元素
的方式查看要爬取网站的网页结构。选取要爬取数据最具特点的内容作为搜索标记(例如下载论文的img),然后制定爬取规则进行爬取。
制定爬取规则是整个爬虫过程最为重要的过程,好的爬取规则可以事半功倍。
例如,在我的爬虫项目中,我们要爬取的目标对象附近总会有一个”PDF”的图像 ,而其他部分没有这个图像
,我们就可以使用这个图像作为我爬取规则的关键字。(这种提取关键字的思想可以参考TF-IDF)
使用好工具
对于一般的小型爬虫项目,使用Request库+BeautifulSoup库是非常方便的。Request库为Python提供一个使用HTTP协议的API,BeautifulSoup库为Python处理HTML格式文件的API,两者结合可以快速完成一般的网络爬取项目。
Requests 允许你发送纯天然,植物饲养的 HTTP/1.1 请求,无需手工劳动。你不需要手动为
URL 添加查询字串,也不需要对 POST 数据进行表单编码。Keep-alive 和 HTTP 连接池的功能是
100% 自动化的,一切动力都来自于根植在 Requests 内部的 urllib3。(更多介绍参考Request中文文档)
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。(更多介绍参考BeautifulSoup中文文档)
编程模板
引入所需要的库
1
2
3import requests #Request库,用以使用HTTP协议
from bs4 import BeautifulSoup # BeautifulSoup库,用以解析HTML格式文件
import time #Time库,用以延时下载(sleep(5)反反爬)其中Time库,用以引入sleep()函数,如果目标网站通过访问间隔进行限制用户访问,一般爬取很容易爬到403禁止访问页面。因此我们需要sleep()函数进行反反爬。
获取目标页面并解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14def GetPage():
try:
url = "yoursite.com" # 你目标网站的URL
headers = {'user-agent': 'Mozilla/5.0'} # 修改头文件欺骗目标站点
r = requests.get(url=url,headers=headers) # 构建HTTP数据包并发送给目标站点
r.raise_for_status() # 检查是否返回正确页面
r.encoding = r.apparent_encoding # 使用最有可能的解码方式进行解码
return r # 返回爬到的数据
except:
return "产生异常"
if __name__ == '__main__':
r = GetPage()
soup = BeautifulSoup(r.text,'html.parser') # 将爬到的数据让BeautifulSoup以html格式解码本项目是爬取某学术会议的论文集,所以并不需要扩散式的爬取,仅需将某页面上的所有论文PDF及其题目摘要爬取下来。
根据具体的爬取规则实现爬取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20for pdf in soup.find_all('img'): # 上接 main 函数
if pdf['src'] == "imagetypes/pdf_logo.gif":
PdfFather = pdf.parent.parent.parent.parent
# 找到论文PDF下载地址
DownloadLink=pdf.parent["href"]
# 找到论文的题目
TitleFather = PdfFather.previous_sibling
Title = GetText(TitleFather.get_text())[0]
# 找到论文的摘要
AbstractFather = PdfFather.next_sibling
AbstractFather = PdfFather.next_sibling
Abstract = 0
for AbstractFather in PdfFather.next_siblings:
if str(type(AbstractFather)) =="<class 'bs4.element.NavigableString'>":
continue
temp = GetText(AbstractFather.get_text()) # 将爬到的摘要前后的空格与回车去掉
Abstract = temp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18def GetText(temp):# 将爬到的摘要前后的空格与回车去掉
first = -1
rear = 0
for i in range(len(temp)):
if temp[i] == '\n' or temp[i] == ' ':
continue
else:
first = i
break
for i in range(len(temp)):
if temp[-(i + 1)] == '\n' or temp[-(i + 1)] == ' ':
continue
else:
rear = -(i + 1)
break
temp = temp[first:rear + 1]
temp = temp.split("\n")
return temp将爬到的东西下载到本地
1
2
3
4
5
6
7
8headers = {'user-agent': 'Mozilla/5.0'}
time.sleep(5)
r = requests.get(url=DownloadLink,headers=headers)
with open(Title+".pdf", "wb") as code:
code.write(r.content)
if Abstract!=None:
with open(Title + ".txt", "w",encoding='utf-8') as code:
code.write(Abstract)
常见错误:
被反爬
由于利用Request库进行GET操作时,HTTP报头会表示客户端为Python,所以很容易被针对。检测HTTP报头Agent字段是最简单的反爬机制,如果目标网站还有其他反爬机制,请参考更多文献。
在本项目中,我们将Agent改为“Mozilla/5.0”即可越过反爬机制。具体代码如下:
1
2
3url = "yoursite.com"
headers = {'user-agent': 'Mozilla/5.0'}
r = requests.get(url=url,headers=headers)编码出错
由于window新建文件的默认编码为GBK,而Request库爬到的数据默认编码为UTF-8,虽然在写入文件时Python会自动将UTF8码转为GBK,但是一些特殊字符是不能转换成功的。因此我们应以UTF8格式新建文件。
1
2with open(Title + ".txt", "w",encoding='utf-8') as code:
code.write(Abstract)BeautifulSoup使用规范
在BeautifulSoup中,可以跨标签寻找子孙,只要我们知道目标标签的标签类型。
例如:通过点取属性的方式能获得当前名字的第一个tag:
1
2soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>但是,在BeautifulSoup中不能跨标签使用.string和.strings参数。
例如:如果tag包含了多个子节点,tag就无法确定
.string
方法应该调用哪个子节点的内容,.string
的输出结果是None
:1
2print(soup.html.string)
# None
幸运的是,我们可以使用get_text()方法获取非叶子结点的所有NavigableString
子孙,并返回一个连接到一起的字符串(而非字符串的集合)。
例如,如果tag中包含多个字符串 [2] ,可以使用 .strings
来循环获取:
1 | for string in soup.strings: |