1.爬虫的基本流程
- 用urllib或是requests库把网页的HTML代码拉到本地
- 用HTMLParser,Xpath,BeautifulSoup等库解析HTML代码,找到想要的东西
2.HTMLParser
廖雪峰的网站看资料
3.urllib
廖雪峰的网站看资料
4.requests
菜鸟教程看资料
#GET方法
import requests
HTML=requests.get("网址",headers={"User-Agent":"浏览器头"})
data=HTML.content.decode()#utf-8的HTML代码
开VPN后爬虫可能会遇到问题,需要加入一下的代码
#先加入如下代码
import urllib3
urllib3.disable_warnings()#加载request.get()前面
#之后任意选下面一种方法
# 压根儿不用这么麻烦,直接两种方式:
# 方法一:
session = requests.Session()
session.trust_env = False
response = session.get('网址')
# 方法二:(多人亲测可以直接结局这个问题)
proxies = { "http": None, "https": None}
requests.get("网址", proxies=proxies)
request可能不太稳定,但用起来比urllib舒服,大概吧。
5.Xpath
看收藏夹下面的博客
from lxml import etree
Xpath=etree.HTML(data)#把html代码晒进去
res=Xpath.xpath("xpath语法")#按xpath语法找到你想要的内容,以列表的形式返回
6.正则表达式
使用正则表达式爬虫时注意加上re.S的参数,不然可能什么都匹配不到
import re
data=re.findall(parttern,string,re.S)
不建议用正则表达式匹配原因如下
- 你在网页看到的HTML和爬虫拉到本地的HTML格式稍有不同
- 正则表达式语法很严格,如果写错了会什么都匹配不到
- 匹配起来太慢了,无法灵活运用HTML的结构
- 出错了也不知道要怎么修
7.把数据写入文件中
# 直接按正常的文件操作即可,根据报错调参
# 1.写HTML格式(默认utf-8)
f=open("Test.text","w",encoding="utf-8")
f.write(HTML)
f.close()
# 2.写普通的数据
f=open("Test.text","w")
f.write(data)#data要是字符串才行,如果用了str强转,需要在open时加encoding参数
#中文数据要先encoding='utf-8',或者直接在vscode里面用utf-8看
如果要下载图片和视频,那么将二进制数据写入文件中即可,注意修改后缀名
8.BeautifulSoup
与Xpath的最大区别是能够把HTML结构切割出来,Xpath只能切割文本或是属性的值
from bs4 import BeautifulSoup
soup=BeautifulSoup(网页内容,'解析方法lxml或是htmlparser')#生成一个解析器
data=soup.find_all("标签名",class_="类名",id="id名字")# 返回所有符合要求的html结构,列表形式
for obj in data:
print(obj.string)#打印文本内容
print(obj["class"])#打印class的属性值,是一个列表
print(obj.name)#标签的名字
BS很简单和Xpath差不多,就是多了个类。find_all后返回的是一个列表,列表中的每个元素都可以看作一个soup同样可以调用find_all
9.获取cookie
cookie是一个登入凭证,有了cookie登入网页就不需要输入密码了
- cookie的获取方法:
- 点击F12进入控制台
- 点击网络
- ctrl+r
- 选择一个类型为document的请求(默认是首个)
- 在header下面代开request header,找到cookie并复制粘贴
10.客户端渲染和服务器渲染
爬虫爬到的是网页的HTML源代码,不是元素下面的代码,元素下面的代码是经过浏览器渲染过的。检查爬虫爬到的网页是否正确查看网页的源代码即可,而不是去看元素,元素是用来解析的
服务器渲染
客户端发送请求时,服务器直接返回一个完整的HTML文件,此时返回的HTML文件和元素下面的html代码完全一样。即获得的是一个已经经过整合的HTML结构和HTML数据
客户端渲染
客户端发送请求时,服务器返回一个没有任何具体内容的HTML文件,客户端接收到这个HTML文件后再自动向服务器再发起一次请求,服务器向客户端传送数据。客户端经过两次请求后获得html结构和html数据,自动在本地整合,最后得到元素下面的源代码。在客户端渲染的情况下,排重爬到的网页源代码和网页元素下面得到代码不一样。
典型例子
- bilibili
- 微博热搜
爬虫爬出奇奇怪怪的东西,第一反应是这个网站是服务器渲染,这时候只需要在network下面找到对应数据的url再爬一次就好了
11.session
requests.session()的方法获得一个session的对象
session的意思是会话的意思。使用session能够自动获取cookie。session和requests的区别是多了一个cookie的属性,能够直接自动存储cookie。
import requests
sess=requests.session()
sess.post(url,data=data)#登入网页
sess.get(url)#从网页中爬取信息
用post还是get在浏览器中看请求的类型,而不是自己决定
12.Post的使用方法
看B站百度翻译爬虫的视频,或是自己的代码
post提交数据的格式是json,json的参数在network->playload
下面看,中文是负载
13.AJAX技术
简单的来说就是客户端渲染,AJAX的最主要特点是页面源代码和元素下方的代码不一样,爬虫抓到的是js脚本
使用selenium避开js脚本
selenium是一个用来模拟浏览器行为的驱动工具,使用selenium爬虫时会自动打开你的浏览器进行运作
参考连接
browser.page_source#获取当前页面源代码
browser.current_url#获取当前页面的url
m
element=browser.find_element(By.xxx,"名字或属性值")#查找元素
使用百度搜索bilibili
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
browser = webdriver.Edge()
browser.get('https://www.baidu.com')
time.sleep(2)
searchbox=browser.find_element(By.ID,"kw")
searchbox.send_keys("bilibili")
button=browser.find_element(By.ID,"su")
time.sleep(2)
button.click()
time.sleep(3)
print(browser.page_source)
print(browser.current_url)
使用无头浏览器时需要增加如下代码
from selenium.webdriver.edge.options import Options
opt=Options()
opt.add_argument("--headless")
opt.add_argument("--disable-gpu")
browser=webdriver.Edge(options=opt)
一般的步骤
- 声明browser对象
- 用browser.find_element找到元素
- 操作元素
14.多进程和多线程爬虫
和普通的多线程和多进程完全一样,就是把run里面的内容变成爬虫程序。多进程才能提高效率,多线程不一定比单线程块
15.代理
修改proxy里面的http和https两个键的值,详情看书,这部分比较麻烦
16.参数与表单
- ?后面的都是参数,再负载中的字符串参数中显示,再requests中对应params。一般get的是params
- 表单,一般来说post对应的是data,再负载中查看
以爬取百度的搜索结果为例:
import requests
from bs4 import BeautifulSoup
url = "https://www.baidu.com/s"
param = {
"wd": "我爱python",#关键字
"pn":0#页数,0表示第一页,10表示第二页,以此类推
}
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36 Edg/103.0.1264.71",
"Cookie": "自己的cookie"
}
req = requests.get(url, params=param, headers=header)
soup = BeautifulSoup(req.text, "lxml")
reslist = soup.find_all("div", class_="result c-container xpath-log new-pmd")#搜索结果必然显示在这个盒子里面(除了视频,广告,百科,贴吧)
for obj in reslist:
# print(obj.find_all('div',class_="c-container")[0].find_all("a"))
print(obj.find_all('div',class_="c-container")[0].find_all("a")[0].text)#搜索结果的标题
协程
单线程中的异步操作,效率比多线程要高,用于下载图片或是视频,文本,频繁进行IO操作时用协程
import requests
import asyncio
import aiohttp
from bs4 import BeautifulSoup
import re
regular = re.compile("com/(.*?).html")
def getPageUrl():
url = "https://xiyouji.5000yan.com/"
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36 Edg/103.0.1264.71"
}
req = requests.get(url, headers=head)
soup = BeautifulSoup(req.text, 'lxml')
liList = soup.find_all('li', class_="menu-item")
pageList = []
for obj in liList:
page = obj.find_all('a')[0]['href']
pageList.append(page)
pageList.pop(0)
pageList.pop(0)
pageList.pop(0)
pageList.pop(0)
print(pageList)
return pageList
async def download(url):
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36 Edg/103.0.1264.71"
}
async with aiohttp.ClientSession() as req:
async with req.get(url, headers=head) as res:
content = await res.content.read()
soup = BeautifulSoup(content, 'lxml')
head = soup.find_all('h2', class_="grap--h2")[0].text
text = soup.find_all('div', class_='grap')[0].text
name = re.findall(regular, url)[0]
with open(str(name) + ".txt", "w", encoding='utf-8') as f:
f.write(head)
f.flush()
f.write("\n")
f.flush()
f.write(text)
print("write" + str(head) + "OK")
async def main(pageList):
task = []
for url in pageList:
fun = download(url)
task.append(asyncio.create_task(fun))
await asyncio.wait(task)
if __name__ == '__main__':
url = getPageUrl()
#下面这段时解决Loop错误的必须
result = main(url)
loop = asyncio.get_event_loop()
loop.run_until_complete(result)
# python3.10在windows上面用如下代码替换loop的那两行
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(main())
需要注意的点
- 多进程爬虫时程序有问题时不会报错,这点很坑爹
- 文件名和网址一定要写对,不要传送一个列表进去爬