爬虫
Zane Lv4

===============================================================

学习内容包括但不限于:requests、re、bs4、xlwt、sqlites3;


  • 关于bs4:主要用到的就是BeautifulSoup()进行实例化还有find_al()对实例进行的查找;

  • re正则表达式:这个更简单一个万金油.*?爬所有好吧;

  • xlwt:一个用来可以保存数据到excel的库,xlwt.workbook()创建工作簿,workbook.add_sheet()创建工作表,使用.write(row,column,data)插入数据

  • sqlite3:.connect(path)连接数据库,.cursor()创建游标,用.execute(sql)执行sql语句,.commit()提交事务,.close()先后关闭游标和数据库。

  • requests:请求网页信息再解码的库,整个爬虫我只用了.get(url,header)请求并接受回应,.decode('code')进行相应字符集解码

OKK!介绍完了用的东西,直接给爷爬好吧。

这次我爬取的内容是一个博客url: https://www.kingname.info/,主要爬取内容就是写文章标题呀,文章链接、正文、种类、时间这种,也是没什么难度。直接去找相应的文本右键检查看相应的标签即可;

requests库的使用
1
2
3
4
5
6
7
8
9
10
11
12
def askUrl(url):
header = {
#模拟浏览器头部信息,向豆瓣服务器发送信息,不然会被禁止访问
"User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122 Safari / 537.36"
}
# 用户代理,表示告诉服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么水平的文件内容)
# #print(url)
# 发出请求,获得回应
response = requests.get(url,headers=header)
# 解码
content = response.content.decode('utf8')
return content #返回的content相当于是整个页面的语言形式。

下面是使用正则爬取大体信息的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      content1 = askUrl(baseurl + "archives/")
#爬取标题
Titles = re.findall('(.*?)', content1, re.DOTALL) #re.DOTALL就是包括\n换行符都被爬取
# 爬取文章时间
Times = re.findall('.*?', content1, re.DOTALL)
# 爬取文章链接
Links = re.findall('', content1, re.DOTALL)
# 爬取文章分类
content2 = askUrl(baseurl)
Kinds = re.findall('(.*?)', content2, re.DOTALL)
for Title,Time,Link,Kind in zip(Titles,Times,Links,Kinds):
datalist1 = {
"Title" : Title, #文章标题
"Time" : Time, #发布时间
"Link" : baseurl + Link, #文章url
"Kind" : Kind #文章类别
}
datalists1.append(datalist1)

根据标签信息爬取相应信息,.*?可以是任意字符任意长度,同时有多个的话,(.*?)表示需要爬取的内容;


使用BeautifulSoup进行对象实例化
1
2
3
4
content3 = askUrl(read_Link)
soup = BeautifulSoup(content3, 'html.parser') # 实例化
bodys = soup.find_all('div', class_="post-body") # 爬取文章正文的html字符,这里输出为一个对象
Codes = soup.find_all('td', class_="code") #根据标签产生两个对象,便于查找相应内容
使用bs4爬取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  # # 在正文中爬取文本信息
# # 在正文中爬取图片url
# # 在正文中爬取code
# # 创建列表最后存取
# ###数据还都在对象中,因此这里将其转化为列表
for body in bodys:
ps = list(body.find_all('p')) # 提取所有文本信息为一个对象;
codes = list(body.find_all('code')) # 提取所有codes为一个对象;
imgs = list(body.find_all('img', {"src": True})) # 提取所有图片为一个对象
read_ps = []
read_imgs = []
read_codes = []
read_Codes = []
# 由于以上信息还都是对象,因此需要对每个数据进行遍历然后提取需要的信息;
for p in ps:
# 因为string只能读取单对便签的纯文本 因此这里选择使用get_text()
read_ps.append(p.get_text())
for img in imgs:
read_imgs.append(img['src']) # 提取特定属性的文本信息
for code in codes:
read_codes.append(code.string) #提取文本信息
for Code in Codes:
read_Codes.append(Code.get_text())

datalist2 = {
"Text": "".join(read_ps), #文本信息
"code": "".join(read_codes), #文本内代码
"img_Link": " ".join(read_imgs), #正文图片链接
"Code": "\n".join(read_Codes) #代码块信息
#这里使用.join函数可以将列表内所有字符串连接用引号内容隔开
}
datalists2.append(datalist2)
使用xlwt保存数据到.xls文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 将文章标题、发布时间、url、分类、文章正文、行内代码、图片url、代码块保存到xls文档中
#创建工作簿
print("数据爬取并保存完毕")
sava_data =xlwt.Workbook(encoding="utf-8",style_compression=0) #创建xlwt对象
#创建工作表
sheet = sava_data.add_sheet("Data_1",cell_overwrite_ok=True)
#------------------填充数据--------------------
#创建行名
col = ("文章标题","文章发布时间","文章链接","文章分类","文章正文","行内代码信息","图片url","代码块",)
for i in range(0, 8):
sheet.write(i, 0, col[i]) #填充列名
for l in range(0, 20):
data1 = datalists1[l]
data2 = datalists2[l]
for j in range(0, 8):
if j == 0:
sheet.write(j , l + 1, data1.get("Title"))
elif j == 1:
sheet.write(j , l + 1, data1.get("Time"))
elif j == 2:
sheet.write(j , l + 1, data1.get("Link"))
elif j == 3:
sheet.write(j , l + 1, data1.get("Kind"))
elif j == 4:
sheet.write(j , l + 1, data2.get("Text"))
elif j == 5:
sheet.write(j , l + 1, data2.get("code"))
elif j == 6:
sheet.write(j , l + 1, data2.get("img_Link"))
elif j == 7:
sheet.write(j , l + 1, data2.get("Code"))
sava_data.save("blog_data.xls")
使用splite3库将数据保存到数据库中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
dbpath = "identifier.sqlite" #设置数据库路径
sql = '''
create table blog_data
(
id integer
constraint blog_data_pk
primary key,
Title text default null,
Time varchar default null,
Link varchar default null,
Kind varchar default null,
Text text default null,
code text default null,
img_Link text default null,
Codes text default null
)
''' # 数据库的sql语言
conn = sqlite3.connect(dbpath) # 链接数据库
cursor = conn.cursor() # 对数据的操作需要通过cursor来实现,即游标
cursor.execute(sql) # 执行sql语句
conn.commit() # 提交事务,不然不能做到真正插入数据
conn.close() # 用于关闭连接,以防止下面紧接着有另外的 查询会产生冲突。

conn = sqlite3.connect(dbpath) # 链接数据库
cur = conn.cursor() # 对数据的操作需要通过cursor来实现,即游标
for i in range(0,20):
data1 = datalists1[i]
data2 = datalists2[i]
sql = "insert into blog_data(id, Title, Time, Link, Kind, Text, code, img_Link, Codes)values(%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" % (i + 1, data1.get("Title"),data1.get("Time"),data1.get("Link"),data1.get("Kind"),data2.get("Text").replace("'"," "),data2.get("code").replace("'"," "),data2.get("img_Link"),data2.get("Code").replace("'"," "))
#print(sql) #测试语句
cur.execute(sql)
conn.commit()
cur.close()
conn.close()

上面.replace()是由于文本信息中含有’’与保存文本的数据库值产生冲突,因此需要替换掉。
datalists1[]保存大体信息;datalists2[]保存详细信息;''.join()函数可以将列表内所有字符串连接用引号内容隔开;


总结一哈

整个代码并不难,理解也很直观,可以加入很多功能比如使用GUI提供一个可视化的交互界面;爬取数据的代码也不是很简洁比较冗余,效率没有很高,因为要在不同的页面跳转;呃。。。没有啦!


由 Hexo 驱动 & 主题 Keep