ReadMe

前半部分内容基于清华大学计算机系2022年暑培,简单介绍了一下html知识。

后半部分详细地介绍了爬虫的实现,配套练习请参考liuydd/crawl-exercises (github.com)

HTML语言基础

在web开发中,HTML通常用于描述网页的内容。

HTML基本格式

HTML文本由层级结构组成,格式:

1
<标签>内容</标签>

举例:

1
2
3
4
5
6
7
8
<body>
<h1>
这是标题
</h1>
<p>
这是段落
</p>
</body>

常用HTML元素

  • <body>:网页主体内容,用来容纳网页上所有可见的HTML元素
  • <h1>:一级标题
  • <p>:段落
  • <ul>…</ul>:无序列表
  • <ol>…</ol>:有序列表
  • <b>…</b>:加粗
  • <i>…</i>:斜体
  • <del>…</del>:删除
  • <a href=’网址’>字</a>:在“字”上添加网址链接
  • <img src=”图片地址” alt=”Loading…” />:在HTML文本中添加
  • <table>:表格

HTTP基本知识

HTTP简介

参考https://www.ruanyifeng.com/blog/2016/08/http.html

HTML方法

GET

GET is used to request data from a specified resource

POST

POST is used to send data to a server to create/update a resource.

HTTP响应状态码

HTTP响应状态码用来表明特定HTTP请求是否成功完成

包括:

  • 信息响应(100-199)
  • 成功响应(200-299)
  • 重定向消息(300-399)
  • 客户端错误响应(400-499)
  • 服务端错误响应(500-599)

若收到的响应不在此列表中,则它为非标准响应,可能是服务器软件的自定义响应

HTTP Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。

Cookie主要用于以下三个方面:

  • 会话状态管理(如用户登录需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

MySQL

进入方式:

win+R+cmd进入命令窗口,输入mysql -u root -p

创建用户时要用小写的create user…

创建新用户

1
2
mysql> create user 'Sheeta'@'localhost' IDENTIFIED BY 'Ydlx0207';
mysql> grant all privileges on *.* to `Sheeta`@'localhost'; #赋予权限

视频(好随意的命名

按ctrl+shift+i进入网页控制台

一般爬的时候带上Cookie和User-Agent,因为很多网站的反爬机制比较严格

SQL

登录创建好的用户账号:输入mysql -u xxx(username) -p

Linux下的MYSQL默认区分表名大小写的,而在windows下表名不区分大小写

爬数据时要关闭代理

re.compile函数用于编译正则表达式,生成一个正则表达式对象供match()和search()这两个函数使用

语法格式:

1
re.compile(pattern[,flags])

pattern:一个字符串形式的正则表达式

flags:可选,表示匹配模式,比如忽略大小写,多行模式等。如re.I(忽略大小写),re.M(多行模式)

……

果然代码还是上手写后才知道自己会不会(sigh

发送请求

get请求:

1
2
import requests
resp=requests.get("xx",headers={"Cookie":xx,"User-Agent":xx})

过滤

法一:正则表达式

可以采用正则表达式过滤得到的信息

常用的正则表达式:

字符 描述
d 代表任意数字,就是阿拉伯数字 0-9 这些玩意。
D 大写的就是和小写的唱反调,d 你代表的是任意数字是吧?那么我 D 就代表不是数字的。
w 代表字母,数字,下划线。也就是 a-z、A-Z、0-9、_。
W 跟 w 唱反调,代表不是字母,不是数字,不是下划线的。
n 代表一个换行。
r 代表一个回车。
f 代表换页。
t 代表一个 Tab 。
s 代表所有的空白字符,也就是上面这个:n、r、t、f。
S 跟 s 唱反调,代表所有不是空白的字符。
A 代表字符串的开始。
Z 代表字符串的结束。
^ 匹配字符串开始的位置。
$ 匹配字符创结束的位置。
. 代表所有的单个字符,除了 n r
[...] 代表在 [] 范围内的字符,比如 [a-z] 就代表 a到z的字母
[^...] 跟 […] 唱反调,代表不在 [] 范围内的字符
{n} 匹配在 {n} 前面的东西,比如: o{2} 不能匹配 Bob 中的 o ,但是能匹配 food 中的两个o。
{n,m} 匹配在 {n,m} 前面的东西,比如:o{1,3} 将匹配“fooooood”中的前三个o。
{n,} 匹配在 {n,} 前面的东西,比如:o{2,} 不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。
* 和 {0,} 一个样,匹配 * 前面的 0 次或多次。 比如 zo* 能匹配“z”、“zo”以及“zoo”。
+ 和{1,} 一个样,匹配 + 前面 1 次或多次。 比如 zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。
和{0,1} 一个样,匹配 ?前面 0 次或 1 次。
a|b 匹配 a 或者 b。
() 匹配括号里面的内容。

**.*?**表示匹配任意字符(对有换行的字符串无效

用python的re库来使用正则表达式:

一:

re.match(匹配规则,需要被过滤的内容,…),如:

1
2
3
4
import re
content='Xian has 100 bananas'
res=re.match('Xi.*(d+)s.*s$',content)
print(res.group(1))

得到0

若将res=re.match(‘Xi.*(d+)s.*s$’,content)改为res=re.match(‘Xi.*?(d+)s.*s$’,content)则可得到100

二:

re.search,用法与re.match类似

扫描字符串,返回匹配成功的第一个结果

三:

re.findall,用法类似

返回所有匹配成功的结果

四:

re.sub,替换字符串里的字符,如

1
2
import re
content=re.sub('d+','250',content)

五:

re.compile,用法类似

将匹配符封装,便于以后复用

法二:BeautifulSoup

给一段HTML代码,如何正则表达式的情况下得到我们想要的内容?

直接将html的源代码传给BeautifulSoup:soup=BeautifulSoup(html_doc,’lxml’)

此时建立了一个对象soup,我们要做的是从这个对象中直接获取我们要的内容

如果用print(soup.title.string)或print(soup.p.string)等类似内容,获取的是html网页标准标签里的内容

更多参考:Beautiful Soup 4.4.0 文档 — Beautiful Soup 4.2.0 documentation (crummy.com)

这个参考文档特别好,不知道怎样实现功能时基本看看就知道了\\

Selenium

reference:https://zhuanlan.zhihu.com/p/462460461

Selenium with Python — Selenium Python Bindings 2 documentation (selenium-python.readthedocs.io)

首先要安装webdriver

Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads
Edge: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Firefox: https://github.com/mozilla/geckodriver/releases
Safari: https://webkit.org/blog/6900/webdriver-support-in-safari-10/

注意!:要安装和浏览器版本一样的.exe,否则会报错

基本用法

1
2
3
4
import os
from selenium import webdriver
#初始化一个Edge浏览器且指定绝对路径
browser=webdriver.Edge('D:\edgedriver_win64\msedgedriver.exe')

即现在browser就是一个浏览器,下面通过调用browser来完成各种方法模拟浏览器的操作

采用get方法,如访问百度首页:

1
browser.get("https://www.baidu.com")
1
2
3
4
5
#设置浏览器全屏
browser.maximize_window()
time.sleep(2)
#刷新页面
browser.close()
1
2
3
4
5
6
#前进后退
browser.get("https://www.taobao.com") #打开淘宝
time.sleep(2)
browser.back() #退回到上一页面,即百度
time.sleep(2)
browser.forward() #前进到淘宝页面

获取页面基础属性

1
2
3
4
print(browser.title) #网页标题
print(browser.current_url) #当前网址
print(browser.name) #浏览器名称
print(browser.page_source) #网页源码,可用beautifulsoup来解析

定位页面元素

即模拟用户进行点击和操作

检查网页,找到搜索框的html结构

用find_element_by()定位搜索框,配合send_keys()输入关键词

常用来定位的属性:id,name,class,tag,link…

1
2
browser.find_element('id','kw').send_keys('python')
time.sleep(2)

注:find_element(‘属性名’,‘属性值’)

)))模糊定位:

1
browser.find_element('partial','')

当这些属性不唯一时,可通过xpath或css来定位

也可以先from selenium.webdriver.common.by import By

再根据find_element(By.ID,’ ‘)来定位

注:By后要跟大写,如ID,CLASS_NAME等

获取页面元素属性

获取属性:get_attribute()

输入文本:send_keys()

点击:click()

模拟百度进行的搜索

1
2
3
4
5
6
7
8
9
10
import os
import time
from selenium import webdriver
browser=webdriver.Edge('D:\edgedriver_win64\msedgedriver.exe')
browser.get("https://www.baidu.com")
time.sleep(2)
browser.find_element('id','kw').send_keys('python')
time.sleep(2)
button=browser.find_element('id','su')
button.click()

清除文本:clear()

回车确认:submit()

单选:先定位需要单选的某个元素,然后点击一下即可

多选:依次定位需要选择的元素,点击

下拉框:to be continued…

多窗口切换

frame切换:

切换到子页面:switch_to.frame()

回到父页面:switch_to.parent_frame()

选项卡切换:

  • current_window_handle:获得当前窗口句柄
  • window_handles:获取所有窗口的句柄到当前会话,返回一个窗口句柄列表
  • switch_to.window():切换窗口句柄

在Windows中,句柄是一个系统内部数据结构的引用。例如当你操作一个窗口时,系统会给你一个该窗口的句柄,通知你,你正在操作142号窗口。

举例:

1
2
3
4
#获取句柄
all_handles=browser.window_handles
#切换窗口,n指切换到哪一个窗口
browser.switch_to.window(all_handles[n])

这样写个循环就可以切换不同窗口了。

模拟鼠标操作

先导入ActionChains:

1
from selenium.webdriver.common.action_chains import ActionChains as AC

左键:click()

右键:context_click()

1
2
3
4
5
#定位到要右击的元素
right_click=browser.find_element('link_text','新闻')
#执行鼠标右键操作
ActionChains(browser).context_click(right_click).perform()
time.sleep(2)

双击:double_click()

1
ActionChains(browser).double_click(double_click).perform()

推拽:drag_and_drop(source,target)

常用于滑块类验证码的操作之类,用find_element()指定开始位置source和结束位置target

悬停:move_to_element()

常配合click()使用

模拟键盘操作

引入Keys()类

1
from selenium.webdriver.common.keys import Keys

先定位到需要操作的元素,然后操作即可

常见操作:

send_keys(Keys.BACK_SPACE):删除键(BackSpace)

send_keys(Keys.SPACE):空格键(Space)

send_keys(Keys.TAB):制表键(TAB)

send_keys(Keys.ESCAPE):回退键(ESCAPE)

send_keys(Keys.ENTER):回车键(ENTER)

send_keys(Keys.CONTRL,'a'):全选(Ctrl+A)

send_keys(Keys.CONTRL,'c'):复制(Ctrl+C)

send_keys(Keys.CONTRL,'x'):剪切(Ctrl+X)

send_keys(Keys.CONTRL,'v'):粘贴(Ctrl+V)

send_keys(Keys.F1):键盘F1

…..

send_keys(Keys.F12):键盘F12

延时等待

若遇到使用ajax加载的网页,页面元素可能不是同时加载出来的,如B站。

此时需要设置延时等待一定时间,确保全部节点都加载出来

强制等待:time.sleep(n),在get操作后执行

隐式等待:implicity_wait()设置等待时间,如果到时间后有元素节点没有加载出来,就会抛出异常。在get操作前执行

显式等待:设置一个等待时间和一个条件,在规定时间内,每隔一段时间查看下条件是否成立,如果成立那么程序就继续执行,否则就抛出一个超时异常。

1
2
3
4
5
6
7
8
9
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
...
browser.get('https://www.baidu.com')
# 设置等待时间10s
wait = WebDriverWait(browser, 10)
# 设置判断条件:等待id='kw'的元素加载完成
input = wait.until(EC.presence_of_element_located((By.ID, 'kw')))
1
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)

driver:浏览器

timeout:最长等待时间

poll_frequency=0.5:每次检测的间隔时间,默认0.5

ignored_exceptions=:超时后抛出的异常信息,默认情况下抛出NoSuchElementException异常