1.获得当前时间字符串:
输入:
import datetime
datetime.datetime.today().strftime(’%Y-%m-%d %H:%M:%S’)
输出字符串:‘2017-12-08 19:55:59’
2.标识浏览器身份的User-Agent:
webheader = {‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36’}
3.bsObj = getObj(pageurl) 的说明:
# 引入Beautiful Soup包
from bs4 import BeautifulSoup
# 把刚刚保存在content中的文件放入Beautiful Soup中
soup = BeautifulSoup(content, ‘lxml’)
【关键】有关BeautifulSoup的网页分割可参考下面的简书,写得超棒:
http://www.jianshu.com/p/9c266216957b
【此处是精细活,也是机械活,重复劳动,细心即可】
【注意想好DataFrame的表现形式,写好爬数据的输出结构】
4.df = pd.DataFrame() 的说明:
DataFrame是pandas的一种框架格式,方便记录信息
可以df.to_html(‘地址’)来输出框架的html网页
Q: html中文打开乱码
A: 在顶部添加:
5.正则表达式讲解:
http://cuiqingcai.com/977.html
20171227
-1.
Q: 如何检查网页元素
A: 在Chrome的网页中,键盘按下 Option + Command + I 即可
0.
Q: 如何使用 BeautifulSoup 的 find 函数
A: find的参数及意义:
find(name=None, attrs={}, recursive=True, text=None, **kwargs)
】】按照tag(标签)搜索:
1) find(tagname) # 直接搜索名为tagname的tag 如:find(‘head’)
2) find(list) # 搜索在list中的tag,如: find([‘head’, ‘body’])
3) find(dict) # 搜索在dict中的tag,如:find({‘head’:True, ‘body’:True})
4) find(re.compile(’’)) # 搜索符合正则的tag, 如:find(re.compile(’^p’)) 搜索以p开头的tag
5) find(lambda) # 搜索函数返回结果为true的tag, 如:find(lambda name: len(name) == 1) 搜索长度为1的tag
6) find(True) # 搜索所有tag
】】按照attrs(属性)搜索:
1) find(‘id’=‘xxx’) # 寻找id属性为xxx的
2) find(attrs={‘id’:re.compile(‘xxx’), ‘algin’:‘xxx’}) # 寻找id属性符合正则且algin属性为xxx的
3) find(attrs={‘id’:True, ‘algin’:None}) # 寻找有id属性但是没有algin属性的
1.解析自定义的 getObj 函数:使用了 import urllib.request
req = urllib.request.Request(url=pageurl, headers=webheader)
↑先定义好一个Request
webPage = urllib.request.urlopen(req)
↑发送此Request,打开网页,得到一个 http.client.HTTPResponse 网页对象
bsObj = BeautifulSoup(webPage, “lxml”)
↑得到了BeautifulSoup分解好的网页元素"Soup"
↑(‘lxml’是告诉它,把webPage作为网页对待)
return 这个"Soup",即bsObj
【另一种requests方法:如果使用 requests 包,需要 import requests】
r = requests.get(url=pageurl, headers = webheader)
↑这一步实现了urllib方法中Request和urlopen两步的功能,返回一个 Response [200] 对象
if r.status_code == requests.codes.ok:
↑通过r.status_code查询响应状态码,200为成功,常见的失败状态码比如404
↑requests.codes.ok为内置的状态码查询对象(成功响应)
bsObj = BeautifulSoup(r.content, “lxml”)
↑虽然与urllib方法句式相同,但与webPage不同的是,r.content 为 bytes 对象;最后的bsObj类型相同
return bsObj
else:
↑响应状态码不为200,则进入else中,不会抛出错误,这与urllib方法使用的 try-except 结构不同
print(’\033[33m Warning:\033[0m Fail to open:’, pageurl)
return None
2.解析自定义的 getDaifu 主函数:
totalposts = int(bsObj.find(“span”, {“class”:“f14 orange1”}).get_text())
↑获得全部患者数(网页橙色数字)
n = bsObj.find(“a”, {“class”:“page_turn_a”,“rel”:“true”}).get_text()
↑获得包含【全部页面数】的文字段
n = int(re.sub(r’[^0-9]’,’’,n))
↑使用正则表达式,得到文字段中的数字;第二个参数’'的用意为删除字符;此处无需使用原生字符串r
【re.sub(替换)用法】 re.sub(pattern, repl, string) 此三参数必选
【[]为字符集,其对应的位置可以是字符集中的任意字符;字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c];[^0-9]表示取反,即非0到9;所有特殊字符在字符集中都会失去其原有的特殊含义,用\反斜杠转义恢复特殊字符的特殊含义】
for i in range(1, n+1): listurl = pageurl + ‘?type=&p=’ + str(i)
↑对每页,输入相应页码的网址
df = df.append(getPosts(listurl), ignore_index=True)
↑使用 getPosts 函数,并使用DataFrame的append方法添加数据
【df.append用法】ignore_index参数为True,可以使新加入的行继续计数
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.append.html
根据上述说明文档,循环中使用 df.append 效率较低,
建议循环建立多个只包含一行的DataFrame,然后使用pd.concat将它们串联到一起
3.解析自定义的 getPosts 函数:
posts = bsObj.find(“div”, {“class”:“zixun_list”}).findAll(“a”, {“class”:“td_link”})
↑获得当前页码的所有提问,得到一个列表,后续可以使用 for post in posts 操作
print(’ Now scraping post’, post[‘href’])
↑('href’意为超链接)将post中含有的超链接网址变量print出来
↑此处也可以使用 post.get(‘href’) 得到超链接网址
QA = getQA(post[‘href’])
QAs.append(QA)
↑进入此超链接地址,调用 getQA 函数;该函数返回字典,装入QAs列表中
df = pd.DataFrame(QAs, columns=[‘xxx’…‘xxx’])
↑QAs列表转换为DataFrame后,各行为QA的内容,按列表堆叠;columns预设好列名称
return df
↑作为该页面的全部内容,返回DataFrame给 getDaifu 函数合并
4.解析自定义的 getQA 函数:
trigger = bsObj.find(class_=‘cblues1’)
↑此程序只针对含有’cblues1’这个class的 nicely formatted Q&A 进行处理,忽略其它QA
【此处find的用法】与之前见到的 bsObj.find(attrs={‘class’:‘cblues1’}) 格式,效果相同
question = trigger.parent.parent
↑向上寻找父节点(两次),得到其所含的所有信息
jibing = question.find(“h2”)
↑注意find只会找得’‘h2’‘第一次出现的地方,而findAll会找得其全部出现的地方
【findAll会找内容中全部符合参数条件的标签位置;而 .<标签名> 只找下一层的该标签位置组成列表】
xxxxxx.get_text().strip()
↑strip可以去掉字符串开头和末尾的所有空白符(包括’\n’、’\r’、’\t’、’ ')
【\n 为回车,然后光标在下一行; \r 为换行,然后光标在此行首,再输出会覆盖光标后的字符】
for reply in block.next_siblings
↑在文档树中,使用 next_sibling 和 previous_sibling 来查询兄弟节点(注意首尾节点)
↑使用 next_siblings 和 previous_siblings 返回该方向全部兄弟节点的列表
【Try-Except-Else的用法】
try:
<语句>
except :
<语句> #如果在try部份引发了名为’name’的异常,则执行这段代码
else:
<语句> #如果没有异常发生,则执行这段代码
5.解析自定义的 getText 函数:
target = bsObj.find(lambda tag: tag.get_text() == feature + ‘:’)
↑搜索冒号后函数值为True的tag,找得feature的所在位置
text = filter(lambda x:x.name != ‘div’ and x.name != ‘script’, target.next_siblings)
↑针对feature所在位置的后续节点,避免可能存在的病例附件节点,得到符合条件节点的列表
【每一个节点的 name 属性返回其节点名(即 tag )】
【lambda(匿名函数)的用法】
lambda 定义一个匿名函数,使代码更简洁,可配合filter、map、reduce等使用:
filter(lambda x: x % 3 == 0, xxxlist) 等价于 [x for x in xxxlist if x % 3 == 0] (首选后者)
map(lambda x: x * 2 + 10, xxxlist) 等价于 [x * 2 + 10 for x in xxxlist] (首选后者)
【实际运用中filter和map不容易用好,易出现问题(比如一次性是咋回事?),故首选后者表达式】【原语句重写为: text = [x for x in target.next_siblings if x.name != ‘div’ and x.name != ‘script’] 】
text = ‘’.join(list(map(str, text))).replace(’
’, ‘’)
↑转换为字符串的列表,再合并进入一个字符串,并删除掉tag名(即br)
【原语句重写为: text = ‘’.join([str(x) for x in text]).replace(’
’, ‘’) 】
text = re.sub(r’<[>]+>([<>])</[^>]+>’, r’\1’, text)
↑删除字符串中的html标签对(一个 和一个 ,且其间没有 < 或 > 符号)
【<[>]+>开始标签,</[>]+>结束标签,([^<>])是编号为1的分组,替换的r’\1’代表1号分组内字符】
【被()括起来的表达式将作为分组,从表达式左边开始每遇到一个分组的左括号’(’,编号+1;另外,分组表达式作为一个整体,可以后接数量词;表达式中的|仅在该组中有效】
【<number>比如\1,代表引用编号为的分组匹配到的字符串(注意要r’\1’)】
【+代表匹配前一个字符1次或无限次】
【*代表匹配前一个字符0或无限次(意即没有字符也没关系)】
text = re.sub(r’\n|\r’, ‘’, text)
↑删除字符串中的 \n 和 \r
【|代表左右表达式任意匹配一个,它总是先尝试匹配左边的表达式,一旦成功则跳过匹配右边;如果|表达式没有被包含在()中,则它的范围是整个正则表达式】
text = re.sub(r’\s+’, ’ ', text).strip()
↑将有1或n个连续空白符的地方,全部替换为一个空格,并strip掉首尾的全部空白符
【\s代表各种空白字符】
【\S代表非空白字符,意即 [^\s] 】