步骤/目录:
无

本文首发于个人博客https://lisper517.top/index.php/archives/4247/,转载请注明出处。
本文的原文写作日期为2020年9月17日,主要目的是总结《Python网络数据采集》。

下面的内容有些缩进或者图片缺失,可以参考 原word文档

1.本书使用标准urllib模块和非标准模块bs4模块:
from urllib.request import urlopen 
from bs4 import BeautifulSoup 
html = urlopen("http://www.pythonscraping.com/pages/page3.html") 
bsObj = BeautifulSoup(html)

2.find_all()方法相关:
find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs) method of bs4.BeautifulSoup instance
第一个参数name为标签名,为None时可匹配所有标签名;
第二个为标签属性,常以字典形式给出;
第三个为是否递归查找,除非十分了解网页格式且有时间要求,一般情况下都取True;
第四个为匹配标签内容;
limit为查找返回个数限制,为1时该方法等同find方法;
最后是一些其他参数。

3.html格式相关:
子节点(children)和后代节点(descendant),子节点仅为下一级的标签,后代节点包含所有下级标签:
for child in bsObj.find("table",{"id":"giftList"}).children: 
print(child)
这些相关节点都是包含空格、换行的,处理时务必去掉
兄弟标签:next_siblings为后续的所有同级标签,previous_siblings相反。这两个都有去掉s的形式。

父标签与祖先标签:parent和parents

4.常用re符号:


5.用attrs方法返回一个标签的所有属性(字典形式)

6.scrapy应用:自学

7.API,应用编程接口,有严格的语法,用XML或json表示数据。
HTTP常用方法:get,请求网页信息;post,用户提交信息;put,请求更新某个数据;delete,请求删除某个数据。

8.使用twitter库获取推文、更新推文等;利用google、baidu提供的API。

9.用urllib.request.urlretrieve下载文件

10.学习mysql
mysql基础命令:
net start mysql 启动sql网络服务;CREATE DATABASE scraping 创建数据库;USE scraping 使用数据库;
>CREATE TABLE pages (id BIGINT(7) NOT NULL AUTO_INCREMENT, title VARCHAR(200), content VARCHAR(10000), created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id));
用以上头创建数据库中的表;
> INSERT INTO pages (title, content) VALUES ("Test page title", "This is some te st page content. It can be up to 10,000 characters long.");
向表中插入数据;
>SELECT * FROM pages WHERE title LIKE "%test%";
查找数据;
删除只需要把对应的SELECT换成DELETE即可。记得先确认,加上WHERE。
>UPDATE pages SET title="A new title", content="Some new content" WHERE id=2;
更新数据。
ALTER DATABASE scraping CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
将scraping数据库的字符集从utf8mb4改为utf8mb4_unicode_ci。

用pymysql在python中使用mysql:
import pymysql
conn = pymysql.connect(host='127.0.0.1',
                       user='root',
                       passwd='aboutime',
                       db='mysql')# 创建连接对象
cur = conn.cursor()# 创建游标对象
cur.execute('USE scraping')# 用execute方法操作数据库
cur.execute('SELECT * FROM pages WHERE id = 3')
print(cur.fetchone())# 查询后用fetchone输出结果
cur.execute("INSERT INTO pages (title, content) VALUES (\"%s\",\"%s\")", (title, content))# 用格式化字符串插入新条目
cur.close()
conn.close()# 一定记得关闭游标对象和连接对象

另外,作者推荐用自己创建的id(而不是具有唯一性的字段)作为key(字典键值对查询可增快速度)

11.配置SMTP客户端后,用smtplib或email模块发送邮件。发送邮件可以随时了解爬虫的工作情况。

12.读取txt:r=urlopen(‘http://xxxxxxxx/test.txt’);chars=r.read();content=chars.decode(encoding=’utf-8’)

utf-8编码:真实情况是,UTF-8 的每个字符开头有一个标记表示“这个字符只用一个字节”或“那个字符需要用两个字节”,一个字符最多可以是四个字节。由于这四个字节里还包含一部分设置信息,用来决定多少字节用做字符编码,所以全部的 32 位(32 位 =4 字节 ×8 位 / 字节)并不会都用,其实最多使用 21 位,也就是总共 2 097 152 种可能里面可以有 1 114 112个字符。

一般网站的meta名标签中可能有charset=’’的属性,可以找到网站编码。

13.读取csv:
将csv文件保存在内存中,将其转换成一个文件对象后读取:
from urllib.request import urlopen
from io import StringIO
import csv
data = urlopen('http://.../test.csv').read().decode('ascii', 'ignore')
datafile = StringIO(data)
csvReader = csv.reader(datafile)
for row in csvReader:
    print(row)

csvReader是可迭代的,且由列表构成。reader也可以用DictReader,详见p86

14.用pdfminer3k处理pdf文件:见p88

15.由于没有好的处理docx库,需要手动处理:见p89
python-docx模块

16.文本内容、分析短语;用openrefine清洗数据:p98
进一步分析文本:p105,去掉常见无意义词

Markov模型:从一个状态转移到另一个状态。从一个状态转出的可能性和为1;下一个状态仅由当前状态决定。可以作为网页的热门度排名,计数一个网站的被引次数。或者用于生成随机文本(胡言乱语模拟器)p108

16.用mysql数据库中爬取的链接数据与有向图,用广度优先搜索解决六度分隔问题:p110

17.用nltk模块分析文本:p114

18.用requests模块执行http操作:
提交表单:表单所在的页面一般是html,提交的标签一般有method=’post’和action=’xxx’,其中xxx才是爬虫提交表单需要接入的接口。子标签中一般有type=’text’之类的东西,尤其注意变量名,比如网页需要提交姓名,子标签中有name=’lastname’,那么就需要用requests的post方法,其中参数data需要一个字典,字典中应该有’lastname’:’xxx’一项。
例:网站http://pythonscraping.com/pages/files/form.html的格式为html,源码为:
<h2>Tell me your name!</h2>
<form method="post" action="processing.php">
First name: <input type="text" name="firstname"><br>
Last name: <input type="text" name="lastname"><br>
<input type="submit" value="Submit" id="submit">
</form>
那么爬虫需要接入:http://pythonscraping.com/pages/files/processing.php,如下:
import requests
params = {'firstname': 'T', 'lastname': 'Bag'}
r = requests.post('http://pythonscraping.com/pages/files/processing.php',
                  data=params)
print(r.text)
r.text就是网页接收表单后返回的数据。

提交文件的方法类似:网页源码
<form action="processing2.php" method="post" enctype="multipart/form-data">
 Submit a jpg, png, or gif: <input type="file" name="image"><br>
 <input type="submit" value="Upload File">
</form>
程序代码:
import requests
files = {'uploadFile': open('../files/Python-logo.png', 'rb')}
r = requests.post("http://pythonscraping.com/pages/processing2.php",
 files=files)
print(r.text)

登录见p125:用户输入用户名和密码,网站返回cookie,接下来都用该cookie访问:
import requests
params = {'username': 'Ryan', 'password': 'password'}
穿越网页表单与登录窗口进行采集 | 125
r = requests.post("http://pythonscraping.com/pages/cookies/welcome.php", params)
print("Cookie is set to:")
print(r.cookies.get_dict())
print("-----------")
print("Going to profile page...")
r = requests.get("http://pythonscraping.com/pages/cookies/profile.php",
 cookies=r.cookies)
print(r.text)

对简单的访问这样处理没有问题,但是如果你面对的网站比较复杂,它经常暗自调整
cookie,或者如果你从一开始就完全不想要用 cookie,该怎么处理呢? Requests 库的
session 函数可以完美地解决这些问题:
import requests
session = requests.Session()
params = {'username': 'username', 'password': 'password'}
s = session.post("http://pythonscraping.com/pages/cookies/welcome.php", params)
print("Cookie is set to:")
print(s.cookies.get_dict())
print("-----------")
print("Going to profile page...")
s = session.get("http://pythonscraping.com/pages/cookies/profile.php")
print(s.text)
在这个例子中,会话(session)对象(调用 requests.Session() 获取)会持续跟踪会话信
息,像 cookie、header,甚至包括运行 HTTP 协议的信息,比如 HTTPAdapter(为 HTTP
和 HTTPS 的链接会话提供统一接口)。

在一些安全性较高的网站可能遇到HTTP基本接入认证,可用requests库的auth模块处理:
import requests
from requests.auth import AuthBase
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth('ryan', 'password')
r = requests.post(url="http://pythonscraping.com/pages/auth/login.php", auth=
 auth)
print(r.text)

19.js简介:javascript是一种弱类型语言。所有变量和函数都用var显式声明(对比python)。Python运行js比较慢,尽量绕开js直接获取数据。

网页常用js库:
Jquery,特征是源码包含jquery入口:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></ 
script>

Google Analytics:特征是页面下方有:<!-- Google Analytics -->
如果一个网站使用了 Google Analytics 或其他类似的网络分析系统,而你不想让网站知道你在采集数据,就要确保把那些分析工具的 cookie 或者所有 cookie 都关掉。

Google地图:类似google.maps.LatLng()

Ajax和DHTML可以使浏览器在同一个url上获得变化的数据,一般都需要浏览器执行js。那些使用了 Ajax 或 DHTML 技术改变 / 加载内容的页面,可能有一些采集手段,但是用Python 解决这个问题只有两种途径:直接从 JavaScript 代码里采集内容,或者用 Python 的第三方库运行 JavaScript,直接采集你在浏览器里看到的页面。
Selenium库可以执行js,需要和一个浏览器一起运行,比如phantomjs无头浏览器(不是python库,类似chrome浏览器,只是没有界面)。如果用chrome或者firefox等,需要执行相应的driver。
from selenium import webdriver
import time
driver = webdriver.PhantomJS(executable_path='相应的driver路径')
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
time.sleep(3)
print(driver.find_element_by_id('content').text)
driver.close()

由于phantomjs已经停止维护,可以使用chrome浏览器的无头模式(v60以上支持):
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)

Selenium库的作用和bs4类似。查找单个元素时,find_element_by_tag_name方法返回匹配的标签名,需要返回列表时写elements即可。不习惯的话可以用driver.page_source返回页面源码,用bs解析该源码。

上面的代码中显式等待了3s,还可以通过让selenium检查页面变化来判断,称为隐式等待:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.PhantomJS(executable_path='')
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
try:
 element = WebDriverWait(driver, 10).until(#等待上限为10s
 EC.presence_of_element_located((By.ID, "loadedButton")))
finally:
 print(driver.find_element_by_id("content").text)
 driver.close()
其中EC是expected condition的缩写,常用简称。
(By.ID, "loadedButton")是一种定位器。定位器的使用见p135

用selenium执行js实现客户端重定向:不断检测页面上一个元素,直到抛出StaleElementReferenceException异常,说明页面刷新了:
from selenium import webdriver
import time
from selenium.webdriver.remote.webelement import WebElement
from selenium.common.exceptions import StaleElementReferenceException
def waitForLoad(driver):
 elem = driver.find_element_by_tag_name("html")
 count = 0
 while True:
 count += 1
 if count > 20:
 print("Timing out after 10 seconds and returning")
 return
 time.sleep(.5)
 try:
 elem == driver.find_element_by_tag_name("html")
 except StaleElementReferenceException:
 return
driver = webdriver.PhantomJS(executable_path='<Path to Phantom Js>')
driver.get("http://pythonscraping.com/pages/javascript/redirectDemo1.html")
waitForLoad(driver)
print(driver.page_source)
每半s检查一次,时限为10s。

20.使用pillow库进行图像处理、tesseract进行文字识别(tesseract可以直接在cmd中运行,或者用pytesseract在python中使用)。另外,numpy含有大量科学计算方法,比如可以将图片表示为像素数组,可以配合tesseract。
P143例子是将图片颜色过滤,然后用tesseract识别。

有兴趣的可以试试训练tesseract识别验证码。

21.用requests的session还可以更改请求头等。可以伪装手机用户访问,比如user-agent改成:User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X)AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257Safari/9537.53

P158介绍了保存cookie等方法。

通过一些用户看不到却在网页源码里的字段,服务器可能轻易识别爬虫并封ip。用selenium中的is_displayed()方法可以判断标签是否隐藏,见p161

22.出现问题怎么办?
首先,如果你从网络服务器收到的页面是空白的,缺少信息,或其遇到他不符合你预期
的情况(或者不是你在浏览器上看到的内容),有可能是因为网站创建页面的 JavaScript
执行有问题。可以看看第 10 章内容。
• 如果你准备向网站提交表单或发出 POST 请求,记得检查一下页面的内容,看看你想提
交的每个字段是不是都已经填好,而且格式也正确。用 Chrome 浏览器的网络面板(快
捷键 F12 打开开发者控制台,然后点击“Network”即可看到)查看发送到网站的 POST
命令,确认你的每个参数都是正确的。
• 如果你已经登录网站却不能保持登录状态,或者网站上出现了其他的“登录状态”异常,
请检查你的 cookie。确认在加载每个页面时 cookie 都被正确调用,而且你的 cookie 在
每次发起请求时都发送到了网站上。
• 如果你在客户端遇到了 HTTP 错误,尤其是 403 禁止访问错误,这可能说明网站已经把
你的 IP 当作机器人了,不再接受你的任何请求。你要么等待你的 IP 地址从网站黑名单
里移除,要么就换个 IP 地址(可以去星巴克上网,或者看看第 14 章的内容)。如果你
确定自己并没有被封杀,那么再检查下面的内容。
♦ 确认你的爬虫在网站上的速度不是特别快。快速采集是一种恶习,会对网管的服务
器造成沉重的负担,还会让你陷入违法境地,也是 IP 被网站列入黑名单的首要原因。
给你的爬虫增加延迟,让它们在夜深人静的时候运行。切记:匆匆忙忙写程序或收
集数据都是拙劣项目管理的表现;应该提前做好计划,避免临阵慌乱。
♦ 还有一件必须做的事情:修改你的请求头!有些网站会封杀任何声称自己是爬虫的
访问者。如果你不确定请求头的值怎样才算合适,就用你自己浏览器的请求头吧。
♦ 确认你没有点击或访问任何人类用户通常不能点击或接入的信息(更多信息请查阅
12.3.2 节)。 ♦ 如果你用了一大堆复杂的手段才接入网站,考虑联系一下网管吧,告诉他们你的目的。
试试发邮件到 webmaster@< 域名 > 或 admin@< 域名 >,请求网管允许你使用爬虫采
集数据。管理员也是人嘛!

23.如何用爬虫+unittest测试网页前端,见p166。Selenium本意是测试网站,可以用其对网页元素进行点击、点击并按住、双击等操作,还可以生成动作链,也可以将一个元素拖放一定距离/到其他元素上,或者将网页截屏。

24.如何改变ip:用the onion router TOR。TOR也是有局限的,务必遵守道德底线。
Pysocks(一个简单的python代理服务器通信模块)可以和TOR搭配使用

25.使用云服务部署爬虫、搭建服务器等。

标签: none

添加新评论