写在前面:刚刚开始学习python,想直接从爬虫入手,下面的内容是摘自书本的笔记以及一些个人感悟和遇到的一些问题。有不对的地方大家一定提出来,谢谢
附上我看的书的PDF:fq3s
试题5:排序函数sorted,item()将字典的键值对转换成元组,然后再组合成一个list的意思,key值是使用operator.itemgetter函数,按照指定的[1]排序,这里[0]是key,[1]是value
# __author: HY
# date: 2019/3/24
# !/uer/bin/python
# coding: UTF-8
import requests
from bs4 import BeautifulSoup
link = "http://www.santostang.com/"
headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers=headers)
soup = BeautifulSoup(r.text, "lxml")
title = soup.find("h1", class_="post-title").a.text.strip()
print(r.text)
with open('title.txt', "a+") as f:
f.write(title)
f.close()
获取豆瓣电影top25的时候,列表那里的class报错语法有误,暂时不知道什么原因,发现上面的代码是有的,把class改成class_就没问题了,可能是作者漏了?
# __author: HY
# date: 2019/3/24
import requests
from bs4 import BeautifulSoup
def get_movies():
# User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko我用的是微软的浏览器,源代码是这样的,但按照书上的打也没问题。
headers = \
{'User-Agent': 'Mozilla/5.0 (Windows NT6.1; Win64; x64)AppleWebKit/537.36 '
'(KHTML, like Gecko)chrome/52.0.2743.82Safari/537.36', 'Host': 'movie.douban.com'}
movie_list = []
for i in range(0, 10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25)
r = requests.get(link, headers=headers, timeout=10)
print(str(i+1), '页响应状态码:', r.status_code)
soup = BeautifulSoup(r.text, "lxml")
div_list = soup.find_all('div', class_='hd')
# div_list = soup.find_all('')
for each in div_list:
movie = each.a.span.text.strip()
movie_list.append(movie)
return movie_list
movies = get_movies()
print(movies)
第四章——动态网页抓取
笔记:
- 爬取动态加载的内容:
- 浏览器审查元素解析地址
- Selenium模拟浏览器抓取
47页的代码,我没有用火狐浏览器,而是用了微软的Edge,报错如下:
selenium.common.exceptions.WebDriverException: Message: ‘MicrosoftWebDriver.exe’ executable needs to be in PATH.Please download from http://go.microsoft.com/fwlink/?LinkId=619687
反正就是缺个驱动的问题,点击报错内容那里的链接下载了适合的驱动
百度一下,参考网友做法,不需要配置环境变量,直接就成功了,借鉴了这篇文章
# __author: HY
# date: 2019/3/25
from selenium import webdriver
driver = webdriver.Edge(r'E:\我的安装\微软驱动\MicrosoftWebDriver.exe')
driver.get("http://www.baidu.com")
print(driver.title)
# time.sleep(5)
# driver.quit()
# driver.get("http://www.dianping.com/search/7/10/pl")
- 好奇怪,发现作者给的的博客的网站都404了,不知道是什么问题
- 51页处注意elementh和elements的区别,加了s会得到一个刘表,可以通过遍历的方法获得其中的每个元素再进行输出。
- 适当的时候要进行sleep一下,因为网络没加载页面这么快,不要贪图方便省略了,有时会因此出错
最后4.4的实验尝试了一下,发现爬到的内容有些乱,没有深究,现在先打基础吧,慢慢来
第五章——解析网页
笔记
HTML解析器
性能
易用性
提取数据的方式
正则表达式
快
较难
正则表达式
BeautifulSoup
快(使用lxml解析)
简单
Find方法
CSS选择器
lxml
快
较难
XPath
CSS选择器
- 常见的正则字符和含义:
模式
描述
.
匹配任意字符,除了换行符
*
匹配前一个字符的0次或多次
+
匹配前一个字符1次或多次
?
匹配前一个字符0次或1次
^
匹配字符串开头
$
匹配字符串末尾
()
匹配括号内的表达式,也表示一个组
\s
匹配空白字符
\S
匹配任何非空白字符
\d
匹配任何数字,等价于[0-9]
\D
匹配任何非数字,等价于[^0-9]
\w
匹配字母数字,等价于[A-Za-z0-9_]
\W
匹配非字母数字,等价于[^A-Za-z0-9_]
[]
用来表示一串字符
- 正则表达式
- 三个方法:
(1)re.match():必须从开头匹配,只能找一个
(2)re.search():全文匹配,但也只能找一个
(3)re.findall():最优选择,返回的是一个列表
- 贪婪模式:.* ——尝试匹配尽可能多的字符
- 非贪婪模式:.*?——尽量匹配尽可能少的字符
- r:代表纯粹字符串,不会对里面的\转译
- BeautifulSoup
- find_all():得到一个列表
- find()
# __author: HY
# date: 2019/3/30
import requests
from bs4 import BeautifulSoup
# 网址
link = "http://www.santostang.com/"
# 消息头
headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
# 获取内容
r = requests.get(link, headers=headers)
# 把获取到的内容变成 BeautifulSoup对象
soup = BeautifulSoup(r.text, "html.parser")
# 找到class是post-title下a标签的文本,去空格
first_title = soup.find("h1", class_="post-title").a.text.strip()
# 输出
print(first_title)
# 找到全部class是post-title的标签,放在一个列表里,遍历输出其中的a标签的文本,去空格
title_list = soup.find_all("h1", class_="post-title")
for i in range(len(title_list)):
title = title_list[i].a.text.strip()
print('第 %s 篇文章的标题是: %s'%(i+1, title))
BeautifulSoup对象是一个复杂的树形结构,每一个节点都是一个python对象,获取网页内容就是一个提取对象的过程。提取对象的方法有三种:
(1)遍历文档树:
获取标签内容:
soup.header.h3#这里的header是有个标签是header
获取子节点列表:
soup.header.div.contents#也可以加上[]代表特定的哪个子节点
获取子节点列表(不能自动输出):
for child in soup.header.div.children: print(child)# 仅获得下一级节点 for child in soup.header.div.descendants: print(child)# 所有节点
获取父节点:
a_tag = soup.header.div.a a_tag.parent
(2)搜索文档树:
find()
find_all()
仅常用上面两个,可以和正则表达式结合使用
for tag in soup.find_all(re.compile("^h")):
print(tag.name)
# 找到所有以h开头的标签。传入正则表达式作参数,BeautifulSoup通过正则的match()方法匹配。
re.compile:参数写正则就会返回匹配的列表
(3)CSS选择器
select()
- lxml
这个没有详细写,所以也没有去认真看了。
PS:因为我稍微看过html、css、js的视频,他们都是用来写网页的,有各种各样的标签,对上面的知识点不存在太大问题,没学过写网页的话可能看网页源代码和python中爬取网页的知识会有些吃力。如果有小伙伴需要写网页的视频可以找我。
第六章——数据存储
- 存储在文件中,TXT,CSV文件
- 存储在数据库中,MySQL关系数据库和MongoDB数据库
将数据写入TXT文件:
# 以a+的方式打开文件test.txt,写入内容。
# 最后我记得是不需要关闭的,这个语法格式会自动关闭,但书上写了
title= “This is a test sentence."
with open (r'D:\test.txt',"a+" as f:
f.wtrite(title)
f.close()
# 用tab将变量分割,如果是大量需要的,在循环里推导一下也行
output= '\t'.join(['name', 'title', 'age', 'gender'])
with open (r'D:\test.txt',"a+") as f:
f.wtrite(output)
f.close()
with open (r'D:\test.txt',"r", encoding = 'UTF-8') as f:
r = f.read()
print(r)
将数据写入CSV文件:
# 详见P83.读取数据:
import csv
with open ('test.csv',"r", encoding = 'UTF-8') as f:
r = csv.read(f)
for row in r
print(r)
print(r[0])
# 写入数据:
import csv
output_list = ['1','2','3','4']
with open ('test.csv',"a+", encoding = 'UTF-8', newline=' ') as f:
r = csv.read(f)
r.writerow(output_list )# 然后用excel打开即可
P103页MongoDB爬虫实践:虎扑论坛
- 我打开查看源文件的时候,看到的数据所在位置和书上给的完全不一样,使用的标签也不一样,很奇怪,也许是虎扑定期更新了?还是说我用不一样浏览器的原因?所以只好自己查看网页源代码然后一一找出位置。我是在2019–3-31这天完成了,顺利爬到了所有内容,以后不知道还会不会改变。
- 我的代码分成了三部分,写在三个不同的.py文件里。要先设置,然后导入才能跨文件使用。
- 报错如下:(大致意思就是找不到那个方法/类)
This inspection detects names that should resolve but don’t. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Top-level and class-level items are supported better than instance items.
参考:
作者:顺顺顺子
原文:https://blog.csdn.net/xiaoshunzi111/article/details/78500100
我右击了整个文件夹,才找到Mark Directory as。
- 然后from DBclass import MongoAPI,从 DBclass 文件中导入 MongoAPI类,from get_hupu import get_data从get_hupu文件导入get_data方法
数据
位置
某帖子所有数据
‘ul’, class_=‘for-list’
其下的所有‘li’
帖子名称
‘a’, class_=“truetit”
帖子链接
‘a’ ,class_=“truetit”>[‘href’]
作者
‘div’, class_=‘author’>a
作者链接
‘div’, class_=‘author’>a[‘href’]
创建时间
-
回复数
‘span’, class_=‘ansour’
浏览数
‘span’, class_=‘ansour’
最后回复用户
‘span’, class_=‘endauthor’
最后恢复时间
‘div’, class_=‘endreply’>a
# __author: HY
# date: 2019/3/31
# P104,本段代码如果去掉最后的导入数据库的代码,可以独立运行,输出第一页咨询
from DBclass import MongoAPI
import requests
from bs4 import BeautifulSoup
import datetime
# import time
# import re
# 测试的时候想着会不会是网速问题,sleep一下,还有contents用不了换成正则试试?所以导入了上面两个包
# 最后都没有用上,但还是保留下来吧,作为一个提醒
def get_page(link):
headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers=headers)
html = r.content
html = html.decode('UTF-8')
soup = BeautifulSoup(html, 'lxml')
return soup
def get_data(post_list):
data_list = []
for post in post_list:
# 查看网页源代码的时候,是class='titlelink box',是两个类名titlelink和box,写一个就行了
title_td = post.find('div', class_='titlelink')
# 获取内容并去空格
title = title_td.find('a', class_="truetit").text.strip()
# 获取其中的链接,href是链接
post_link = title_td.find('a', class_="truetit")['href']
# 观察,拼接,得到每个子连接
post_link = 'https://bbs.hupu.com'+post_link
author = post.find('div', class_='author').a.text.strip()
author_page = post.find('div', class_='author').a['href']
# 按照课本格式,时间获取为\n,报错
# start_data = post.find('div', class_='author').contents[2]# 注意那个
也是一个元素,所以索引是2
# 做了以下测试,发现确实是没有获得到时间的内容contents有问题,连同下面那个也是一样的问题
# if start_data == '\n':
# start_data = '2019-03-31'
# 一开始尝试把contents换成children,但是也报错了,children[2]不是object is not subscriptable可下标访问,
# 于是用下列遍历的方法:
# i = 1
# for data in start_datas:
# if i == 2:
# start_data = data.text
# else:
# i = i+1
# 尝试通过
# 又琢磨了一下,发现下面这样更简单,找到所有a标签,取第二个的文本:
start_data = post.find('div', class_='author').find_all('a')[1].text
start_data = datetime.datetime.strptime(start_data, '%Y-%m-%d').date()
reply_view = post.find('span', class_='ansour').text.strip()
reply = reply_view.split('/')[0].strip()
view = reply_view.split('/')[1].strip()
reply_time = post.find('div', class_='endreply').a.text.strip()
# 这里用contents也有问题,于是用直接span标签,上面的没有直接取a标签是因为那个a标签没有自己的名字
last_reply = post.find('span', class_='endauthor').text
if ':' in reply_time:
date_time = str(datetime.date.today()) + ' ' + reply_time
date_time = datetime.datetime.strptime(date_time, '%Y-%m-%d %H:%M')
else:
date_time = datetime.datetime.strptime('2017-' + reply_time, '%Y-%m-%d').date()
data_list.append([title, post_link, author, author_page, start_data, reply, view, last_reply, date_time])
return data_list
link = 'https://bbs.hupu.com/bxj'
soup = get_page(link)
post_list = soup.find('ul', class_='for-list')
post_list = post_list.find_all('li')
# print(len(post_list))
date_list = get_data(post_list)
# print(len(date_list))
for each in date_list:
print(each)
# 插入数据库的代码
hupu_post = MongoAPI('localhost', 27017, "hupu", 'post')
for each in date_list:
hupu_post.add({'title':each[0],
"post_link": each[1],
"author": each[2],
"author_page": each[3],
"start_date": str(each[4]),
"reply": each[5],
"view": each[6],
"last_reply": each[7],
"last_reply_time": str(each[8])})
# __author: HY
# date: 2019/3/31
from pymongo import MongoClient
class MongoAPI(object):
def __init__(self, db_ip, db_port, db_name, table_name):
self.db_ip = db_ip
self.db_port = db_port
self.db_name = db_name
self.table_name = table_name
self.conn = MongoClient(host=self.db_ip, port=self.db_port)
self.db = self.conn[self.db_name]
self.table = self.db[self.table_name]
# 获取数据库中的一条资料
def get_one(self, query):
return self.table.find_one(query, projection={'_id': False})
# 获取数据库中满足条件的所有数据
def get_all(self, query):
return self.table.find(query)
# 向集合中添加数据
def add(self, kv_dict):
return self.table.insert(kv_dict)
# 删除集合中的数据
def delete(self, query):
return self.table.delete_many(query)
# 查看集合中是否包含满足条件的数据
def check_exist(self, query):
ret = self.table.find_one(query)
return ret != None
# 更新集合中的数据,如果没有会新建
def update(self, query, kv_dict):
self.table.update_one(query, {
'$set': kv_dict
}, upsert=True)
# __author: HY
# date: 2019/3/31
from DBclass import MongoAPI
from get_hupu import get_page
from get_hupu import get_data
import requests
from bs4 import BeautifulSoup
import datetime
import time
hupu_post = MongoAPI('localhost', 27017, "hupu", 'post')
for i in range(1, 6):
link = "https://bbs.hupu.com/bxj-" + str(i)
soup = get_page(link)
post_list = soup.find('ul', class_='for-list')
post_list = post_list.find_all('li')
date_list = get_data(post_list)
for each in date_list:
hupu_post.update({"post_link": each[1]}, {'title': each[0],
"post_link": each[1],
"author": each[2],
"author_page": each[3],
"start_date": str(each[4]),
"reply": each[5],
"view": each[6],
"last_reply": each[7],
"last_reply_time": str(each[8])})
time.sleep(3)
print('第', i, "页获取完成,休息三秒")
最后补充一句,MongoDB数据库的安装是傻瓜式,比较简单,快完成的时候有个弹窗说要什么privilege,直接把360关闭重新安装,一切顺利~(很多时候都是360或者是防火墙的问题)