接,基础篇,链接:python爬虫入门(所有演示代码,均有逐行分析!)-CSDN博客
目录
1.爬取博客网站全部文章列表
ps:补充(正则表达式)
爬虫实现
爬虫代码:
2.爬取豆瓣电影top250榜
爬虫代码:
3.爬取北京天气十年数据
爬虫代码:
1.爬取博客网站全部文章列表
ps:补充(正则表达式)
PS:这里涉及到python基础语法中正则表达式的内容
课:第三阶段-09-正则表达式-基础方法_哔哩哔哩_bilibili
实例代码:
import re
url1 = "http://www.crazyant.net/1234.html"
url2 = "http://www.crazyant.net/1234.html#comments"
url3 = "http://www.baidu.com"
pattern = r'^http://www.crazyant.net/\d+.html$'
#r;使\d这类转义字符作为一个整体出现,而不是分开的\+d的意思;\d表示一个十进制的数字 [0-9],\d+代表十进制的数字有多个
print(re.match(pattern,url1)) #ok
print(re.match(pattern,url2)) #none
print(re.match(pattern,url3)) #none
运行结果图:
爬虫实现
创建Python Package,命名为blog_test
在package下创建url_manager.py文件,用于存放url管理器模块代码
url管理器代码:
class UrlManager():
'''
url管理器
'''
def __init__(self):
#定义一个初始化函数
self.new_urls = set()
#新的待爬取url的集合
self.old_urls = set()
#已爬取url的集合
def add_new_url(self, url):
#定义新增单个url的方法一,传一个参数url
if url is None or len(url) == 0:
#判断url是否为空或长度为0
return
#符合上述条件就停止增加
if url in self.new_urls or url in self.old_urls:
#判断url是否已经被记录在集合里
return
#已经载集合里的url不新增
self.new_urls.add(url)
#上述干扰条件排除后,url就可以加入待爬取的集合中
def add_new_urls(self,urls):
#定义新增url的方法二,传一个参数urls
if urls is None or len(urls) == 0:
#判断参数urls是否为空
return
for url in urls:
#不为空就将单个url循环传入单个判断url方法中经行判断存储
self.add_new_url(url)
def get_url(self):
#定义获取新url的函数
if self.has_new_url():
#如果存在待爬取的url
url = self.new_urls.pop()
#就将待爬取的url从集合中移除并返回
self.old_urls.add(url)
#将移除的url加入已爬取的集合中
return url
#并将其返回
else:
return None
def has_new_url(self):
#定义一个判断url是否存在等待爬取的url
return len(self.new_urls) > 0
#如果待爬取集合中有元素就分返回这个集合
'''测试代码'''
if __name__ == "__main__":
#文件内置变量,仅在执行当前文件时可用。当此文件被调用时,此出变量不会被执行。因此测试代码时一般加上这句话
url_manger = UrlManager()
#调用整个类
url_manger.add_new_url("url1")
url_manger.add_new_urls(["url1", "url2"])
#故意增加一个重复的url
print(url_manger.new_urls, url_manger.old_urls)
print("#" * 30)
new_url = url_manger.get_url()
print(url_manger.new_urls, url_manger.old_urls)
print("#" * 30)
new_url = url_manger.get_url()
print(url_manger.new_urls, url_manger.old_urls)
print("#" * 30)
print(url_manger.has_new_url())
在package下创建craw_all_pages.py文件,用于存放爬虫代码
爬虫代码:
import url_manager
import requests
from bs4 import BeautifulSoup
import re
root_url = "http://www.crazyant.net"
urls = url_manager.UrlManager()
#引入之前的url管理器模块
urls.add_new_url(root_url)
#初始化url管理器
fout = open("craw_all_pages.txt", "w", encoding="utf-8")
#初始化文件,打开文件定义为可写入模式
while urls.has_new_url():
#如果有新的uel
curr_url = urls.get_url()
#循环获取url
r = requests.get(curr_url, timeout=3)
#爬取获取到的url,同时定义timeout=3,防止页面卡死
if r.status_code != 200:
#如果状态码不是200,
print("error,return status_code is not 200", curr_url)
#输出上面的句子,和当前的url
continue
soup = BeautifulSoup(r.text, "html.parser")
#获取url的所有内容
title = soup.title.string
#soup.tite快速获取title节点,.string得到title里面的文字
fout.write("%s\t%s\n" % (curr_url, title))
# %s将字符串按照指定格式输出;\t:空格;\n:换行;%(curr_url, title)将前面的内容传入后面
fout.flush()
# 内存中的数据刷到磁盘里
print("success:%s, %s, %d" % (curr_url, title, len(urls.new_urls)))
links = soup.find_all("a")
# 找到所有的a节点
for link in links:
href = link.get("href")
# 获取href标签中的所有内容
if href is None:
# 如果href中没有内容
continue
# 跳过并继续执行
pattern = r"^http://www.crazyant.net/\d+.html$"
if re.match(pattern, href):
#字符串匹配查找,看看href格式是否与我们所需数据格式一致
urls.add_new_url(href)
#将找到的href添加到
fout.close()
运行结果:
2.爬取豆瓣电影top250榜
爬取内容:榜单数,标题,评分和评价人数。
查看豆瓣250的url,可以看到每一页都不一样,间隔25,最后一页start=225
查找需要爬取的信息 :电影排行、电影名称、电影评分和评价人数。
爬虫代码:
1.使用requests爬取网页
2.使用BeautifulSoup实现数据解析
3.借助pandas将数据写出到Excel
import requests
from bs4 import BeautifulSoup
import pandas as pd
import pprint
#构造分页数字列表
page_indexs = range(0, 250, 25) #从0开始到250,取不到250,每个25个数字取一个,形成一个可迭代的对象而不是列表
list(page_indexs) #构造列表
#需要将User-agent修改成自己的
headers = {
'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0'
}
def downlode_all_htmls():
'''
下载所有列表页面的HTML,用于后续的分析
'''
htmls = []
for idx in page_indexs:
url = f"http://movie.douban.com/top250?start={idx}&filter="
print("craw html:",url)
r = requests.get(url,headers=headers)
if r.status_code != 200:
raise Exception("error")
htmls.append(r.text)
return htmls
#执行爬取
htmls = downlode_all_htmls()
def parse_single_html(html):
'''
解析单个HTML,得到数据
@return list({"link","title",[label]})
'''
soup = BeautifulSoup(html, 'html.parser')
#获取每个电影的信息
article_items = (
soup.find("div",class_="article")
.find("ol",class_="grid_view")
.find_all("div",class_="item")
)
datas = []
for article_item in article_items:
#排序数字
rank = article_item.find("div",class_="pic").find("em").get_text()
#分步实现,首先获取文章的info
info = article_item.find("div",class_="info")
#然后获取标题
title = info.find("div",class_="hd").find("span",class_="title").get_text()
#获取五星评级、评分、评价人数,span有4个,所以使用find_all
stars = (
info.find("div",class_="bd")
.find("div",class_="star")
.find_all("span")
)
#星级为第一个span
rating_star = stars[0]["class"][0]
#评分为第二个span
rating_num = stars[1].get_text()
#评分人数为最后一个span
comments = stars[3].get_text()
datas.append({
"rank":rank,
"title":title,
"rating_star":rating_star.replace("rating","").replace("-t",""), #去掉前缀和后缀
"rating_num":rating_num,
"comments":comments.replace("人评价","") #把人评价去掉
})
return datas
#pprint可以漂亮的打印数据
pprint.pprint(parse_single_html(htmls[0]))
#执行所有的HTML页面的解析
all_datas = []
for html in htmls:
all_datas.extend(parse_single_html(html))
print(all_datas)
print(len(all_datas))
df = pd.DataFrame(all_datas)
print(df)
#这里想直接输出excel需要安装openpyxl库
df.to_excel("豆瓣电影TOP250.xlsx")
3.爬取北京天气十年数据
爬取目标:http://tianqi.2345.com/wea_history/54511.htm
涉及技术:
headers中设置user agent反爬机制
通过network抓包,分析ajax的请求和参数
通过for循环请求不同的参数的数据
利用pandas实现excel的合并与保存
首先进入网站,更换年份、月份,发现网站地址没有改变
可以判断出,网页存在隐藏的步奏,需要对网页进行抓包操作
右键检查,选择网络(network),不关闭页面的同时,点击更改年份,抓包获取数据
点击获取到的数据,在请求头中找到Uer_Agent,也可以看到请求方式为get
查看请求参数
查看响应内容
爬取网址
爬虫代码:
import time
import requests
import pandas as pd
from numpy.random import random
import random
#设置随机休眠时间,防止ip被禁
time.sleep(random.random()*3)
url = "http://tianqi.2345.com/Pc/GetHistory"
#请求头,防拦截
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.454.400 QQBrowser/13.2.6134.400",
"Cookie":"Hm_lvt_a3f2879f6b3620a363bec646b7a8bcdd=1729388880; HMACCOUNT=52D6CD0BBA8BE5AD; Hm_lpvt_a3f2879f6b3620a363bec646b7a8bcdd=1729388945",
"Referer":"http://tianqi.2345.com/wea_history/54511.htm"
}
def craw_table(year, month):
"""提供年费烦恼和月份爬取对应的表格数据"""
#将参数传过来
params = {
"areaInfo[areaId]": 54511,
"areaInfo[areaType]": 2,
"date[year]": year,
"date[month]": month
}
resp = requests.get(url, headers=headers, params=params)
data = resp.json()["data"]
#解析网页中所有的表格,取第一个元素
df = pd.read_html(data)[0]
return df
df_list = []
for year in range(2014, 2024):
for month in range(1,13):
print("爬取:",year, month)
df = craw_table(year,month)
df_list.append(df)
pd.concat(df_list).to_excel("北京10年天气数据.xlsx",index=False)